Implement QSV encoder flushing
parent
b10db96dc0
commit
9014a4fecf
|
@ -63,6 +63,9 @@ struct Encoder
|
|||
|
||||
std::wstring event_prefix;
|
||||
|
||||
ipc_encoder_flushed encoder_flushed;
|
||||
bool flushed;
|
||||
|
||||
ipc_bitstream_buff bitstream;
|
||||
ipc_filled_bitstream filled_bitstream;
|
||||
ipc_bitstream_info bs_info;
|
||||
|
@ -96,7 +99,7 @@ struct Encoder
|
|||
|
||||
Encoder(IPCSignalledType<init_request> &init_req, std::wstring event_prefix, std::wofstream &log_file)
|
||||
: use_cbr(init_req->use_cbr), first_frame(true), frame_time_ms(static_cast<unsigned>(1./init_req->fps*1000)), exit_code(0)
|
||||
, using_d3d11(false), session(), encoder(session), event_prefix(event_prefix), log_file(log_file)
|
||||
, using_d3d11(false), session(), encoder(session), event_prefix(event_prefix), encoder_flushed(event_prefix + ENCODER_FLUSHED), flushed(false), log_file(log_file)
|
||||
{
|
||||
params.Init(init_req->target_usage, init_req->profile, init_req->fps, init_req->keyint, init_req->bframes, init_req->width, init_req->height, init_req->max_bitrate,
|
||||
init_req->buffer_size, init_req->use_cbr);
|
||||
|
@ -301,6 +304,9 @@ struct Encoder
|
|||
if(result == MFX_WRN_IN_EXECUTION)
|
||||
return;
|
||||
|
||||
if (flushed)
|
||||
return;
|
||||
|
||||
bitstream_info &info = bs_info[encoded_tasks.front()];
|
||||
info.time_stamp = task.bs.TimeStamp;
|
||||
info.data_length = task.bs.DataLength;
|
||||
|
@ -317,10 +323,14 @@ struct Encoder
|
|||
}
|
||||
filled_bitstream.signal();
|
||||
|
||||
msdk_locked_tasks.emplace_back(std::make_pair(task.surf, task.frame_index));
|
||||
task.surf = nullptr;
|
||||
idle_tasks.emplace(encoded_tasks.front());
|
||||
encoded_tasks.pop();
|
||||
|
||||
if (!task.surf)
|
||||
return;
|
||||
|
||||
msdk_locked_tasks.emplace_back(std::make_pair(task.surf, task.frame_index));
|
||||
task.surf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,6 +401,21 @@ struct Encoder
|
|||
task.bs.DataLength = 0;
|
||||
task.bs.DataOffset = 0;
|
||||
|
||||
if(oldest->request_keyframe)
|
||||
task.ctrl = &keyframe_ctrl;
|
||||
else
|
||||
task.ctrl = nullptr;
|
||||
|
||||
if(first_frame)
|
||||
task.ctrl = &sei_ctrl;
|
||||
first_frame = false;
|
||||
|
||||
if (oldest->flush)
|
||||
{
|
||||
task.surf = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
task.surf = idle_surfaces.front();
|
||||
idle_surfaces.pop();
|
||||
|
||||
|
@ -415,15 +440,6 @@ struct Encoder
|
|||
}
|
||||
task.surf->Data.TimeStamp = oldest->timestamp;
|
||||
task.frame_index = oldest->frame_index;
|
||||
|
||||
if(oldest->request_keyframe)
|
||||
task.ctrl = &keyframe_ctrl;
|
||||
else
|
||||
task.ctrl = nullptr;
|
||||
|
||||
if(first_frame)
|
||||
task.ctrl = &sei_ctrl;
|
||||
first_frame = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,6 +452,15 @@ struct Encoder
|
|||
{
|
||||
auto sts = encoder.EncodeFrameAsync(task.ctrl, task.surf, &task.bs, &task.sp);
|
||||
|
||||
if (sts == MFX_ERR_MORE_DATA && !task.surf)
|
||||
{
|
||||
encoder_flushed.signal();
|
||||
flushed = true;
|
||||
idle_tasks.push(queued_tasks.front());
|
||||
queued_tasks.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(sts == MFX_ERR_NONE || (MFX_ERR_NONE < sts && task.sp))
|
||||
break;
|
||||
if(sts == MFX_WRN_DEVICE_BUSY)
|
||||
|
|
|
@ -60,6 +60,9 @@ typedef IPCSignalledType<spspps_size> ipc_spspps_size;
|
|||
#define STOP_REQUEST L"stop"
|
||||
typedef IPCSignal<true> ipc_stop;
|
||||
|
||||
#define ENCODER_FLUSHED L"encoder_flushed"
|
||||
typedef IPCSignal<true> ipc_encoder_flushed;
|
||||
|
||||
|
||||
|
||||
#define EXIT_INIT_IPC_FAILED 1
|
||||
|
|
|
@ -69,6 +69,7 @@ struct queued_frame
|
|||
{
|
||||
bool is_new;
|
||||
bool request_keyframe;
|
||||
bool flush;
|
||||
mfxU64 timestamp;
|
||||
uint32_t frame_index;
|
||||
};
|
||||
|
|
|
@ -241,7 +241,9 @@ namespace
|
|||
|
||||
if (init_pts.Num() || frames_out == 0)
|
||||
init_pts << ts;
|
||||
dts << ts;
|
||||
|
||||
if (!dts.Num() || dts.FindValueIndex(ts) == INVALID)
|
||||
dts << ts;
|
||||
}
|
||||
|
||||
int64_t operator()(uint64_t bs_pts, int64_t bs_dts)
|
||||
|
@ -338,6 +340,8 @@ class QSVEncoder : public VideoEncoder
|
|||
qsvhelper_thread;
|
||||
ipc_stop stop;
|
||||
|
||||
ipc_encoder_flushed encoder_flushed;
|
||||
|
||||
ipc_bitstream_buff bs_buff;
|
||||
ipc_bitstream_info bs_info;
|
||||
struct encode_task
|
||||
|
@ -632,6 +636,10 @@ public:
|
|||
if(!stop)
|
||||
CrashError(TEXT("Failed to initialize QSV stop signal (%u)"), GetLastError());
|
||||
|
||||
encoder_flushed = ipc_encoder_flushed((event_prefix + ENCODER_FLUSHED).Array());
|
||||
if (!encoder_flushed)
|
||||
CrashError(L"Failed to initialize QSV encoder flushed signal (%u)", GetLastError());
|
||||
|
||||
filled_bitstream_waiter = process_waiter;
|
||||
filled_bitstream_waiter.push_back(filled_bitstream.signal_);
|
||||
|
||||
|
@ -934,11 +942,8 @@ public:
|
|||
Log(TEXT("Error: all frames are in use"));
|
||||
}
|
||||
|
||||
void QueueEncodeTask(mfxFrameSurface1 *pic)
|
||||
void QueueEncodeTask(mfxFrameSurface1 *pic, DWORD in_pts)
|
||||
{
|
||||
if (!pic)
|
||||
return;
|
||||
|
||||
profileSegment("QueueEncodeTask");
|
||||
encode_task& task = encode_tasks[idle_tasks[0]];
|
||||
|
||||
|
@ -957,11 +962,19 @@ public:
|
|||
info.request_keyframe = bRequestKeyframe;
|
||||
bRequestKeyframe = false;
|
||||
|
||||
info.timestamp = task.surf.Data.TimeStamp = timestampFromMS(pic->Data.TimeStamp);
|
||||
dts_gen.add(info.timestamp);
|
||||
info.frame_index = (uint32_t)pic->Data.MemId-1;
|
||||
auto lock_status = lock_mutex(frame_buff_status);
|
||||
frame_buff_status[info.frame_index] += 1;
|
||||
if (!pic)
|
||||
{
|
||||
info.flush = true;
|
||||
dts_gen.add(timestampFromMS(in_pts));
|
||||
}
|
||||
else
|
||||
{
|
||||
info.timestamp = task.surf.Data.TimeStamp = timestampFromMS(pic->Data.TimeStamp);
|
||||
dts_gen.add(info.timestamp);
|
||||
info.frame_index = (uint32_t)pic->Data.MemId - 1;
|
||||
auto lock_status = lock_mutex(frame_buff_status);
|
||||
frame_buff_status[info.frame_index] += 1;
|
||||
}
|
||||
frame_queue.signal();
|
||||
return;
|
||||
}
|
||||
|
@ -990,7 +1003,7 @@ public:
|
|||
bool queued = false;
|
||||
if (idle_tasks.Num())
|
||||
{
|
||||
QueueEncodeTask((mfxFrameSurface1*)picInPtr);
|
||||
QueueEncodeTask((mfxFrameSurface1*)picInPtr, outputTimestamp);
|
||||
queued = true;
|
||||
}
|
||||
|
||||
|
@ -1003,7 +1016,7 @@ public:
|
|||
profileOut;
|
||||
|
||||
if(!queued)
|
||||
QueueEncodeTask((mfxFrameSurface1*)picInPtr);
|
||||
QueueEncodeTask((mfxFrameSurface1*)picInPtr, outputTimestamp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1097,7 +1110,7 @@ public:
|
|||
|
||||
virtual bool HasBufferedFrames()
|
||||
{
|
||||
return false;
|
||||
return !encoder_flushed.is_signalled();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue