Implement QSV encoder flushing

master
palana 2014-08-10 03:32:58 +02:00
parent b10db96dc0
commit 9014a4fecf
4 changed files with 67 additions and 25 deletions

View File

@ -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)

View File

@ -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

View File

@ -69,6 +69,7 @@ struct queued_frame
{
bool is_new;
bool request_keyframe;
bool flush;
mfxU64 timestamp;
uint32_t frame_index;
};

View File

@ -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();
}
};