198 lines
5.6 KiB
C++
Raw Normal View History

2023-07-15 03:07:19 +08:00
#include "FFMPEGDecoder.h"
FFMPEGDecoder::FFMPEGDecoder() {
decoder_reorder_pts = -1;
queue = NULL;
avctx = NULL;
pkt_serial = -1;
finished = 0;
packet_pending = false;
empty_queue_cond = NULL;
start_pts = 0;
start_pts_tb = {0,0};
next_pts = 0;
next_pts_tb = {0, 0};
decoder_tid = NULL;
}
FFMPEGDecoder::~FFMPEGDecoder()
{
}
void FFMPEGDecoder::Init(AVCodecContext *_avctx, FFMPEGPacketQueue *_queue, CondWait *_empty_queue_cond) {
this->avctx = _avctx;
this->queue = _queue;
this->empty_queue_cond = _empty_queue_cond;
this->start_pts = AV_NOPTS_VALUE;
this->pkt_serial = -1;
}
int FFMPEGDecoder::DecodeFrame( AVFrame *frame, AVSubtitle *sub) {
int ret = AVERROR(EAGAIN);
for (;;) {
AVPacket pkt;
if (queue->GetSerial() == pkt_serial) {
do {
if (queue->IsAbortRequest())
return -1;
switch (avctx->codec_type) {
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_receive_frame(avctx, frame);
if (ret >= 0) {
if (decoder_reorder_pts == -1) {
frame->pts = frame->best_effort_timestamp;
}
else if (!decoder_reorder_pts) {
frame->pts = frame->pkt_dts;
}
}
break;
case AVMEDIA_TYPE_AUDIO:
ret = avcodec_receive_frame(avctx, frame);
if (ret >= 0) {
AVRational tb = { 1, frame->sample_rate };
if (frame->pts != AV_NOPTS_VALUE)
frame->pts = av_rescale_q(frame->pts, avctx->pkt_timebase, tb);
else if (next_pts != AV_NOPTS_VALUE)
frame->pts = av_rescale_q(next_pts, next_pts_tb, tb);
if (frame->pts != AV_NOPTS_VALUE) {
next_pts = frame->pts + frame->nb_samples;
next_pts_tb = tb;
}
}
break;
}
if (ret == AVERROR_EOF) {
finished = pkt_serial;
avcodec_flush_buffers(avctx);
return 0;
}
if (ret >= 0)
return 1;
} while (ret != AVERROR(EAGAIN));
}
do {
if (queue->GetNumPackets() == 0)
empty_queue_cond->signal();
if (packet_pending) {
av_packet_move_ref(&pkt, &pkt);
packet_pending = false;
}
else {
if (queue->Get(&pkt, 1, &pkt_serial) < 0)
return -1;
}
} while (queue->GetSerial() != pkt_serial);
if (FFMPEGPacketQueue::IsFlushPacket(pkt.data)) {
avcodec_flush_buffers(avctx);
finished = 0;
next_pts = start_pts;
next_pts_tb = start_pts_tb;
}
else {
if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
int got_frame = 0;
ret = avcodec_decode_subtitle2(avctx, sub, &got_frame, &pkt);
if (ret < 0) {
ret = AVERROR(EAGAIN);
}
else {
if (got_frame && !pkt.data) {
packet_pending = 1;
av_packet_move_ref(&pkt, &pkt);
}
ret = got_frame ? 0 : (pkt.data ? AVERROR(EAGAIN) : AVERROR_EOF);
}
}
else {
if (avcodec_send_packet(avctx, &pkt) == AVERROR(EAGAIN)) {
av_log(avctx, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
packet_pending = 1;
av_packet_move_ref(&pkt, &pkt);
}
}
av_packet_unref(&pkt);
}
}
return ret;
}
void FFMPEGDecoder::SetDecoderReorderPts ( int pts ) {
decoder_reorder_pts = pts;
}
void FFMPEGDecoder::Destroy() {
avcodec_free_context(&avctx);
avctx = NULL;
}
void FFMPEGDecoder::Abort(FFMPEGFrameQueue* fq) {
queue->Abort();
fq->Signal();
try {
if (decoder_tid->joinable()) {
decoder_tid->join();
}
}
catch (std::system_error &) {
}
delete decoder_tid;
queue->Flush();
}
int FFMPEGDecoder::Start(std::function<int (void *)> thread_func, void *arg ) {
queue->Start();
std::thread cpp_thread(thread_func, arg);
decoder_tid = new std::thread(std::move(cpp_thread));
if (!decoder_tid) {
//av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
#ifdef TARGET_WIN32
HANDLE hThread = decoder_tid->native_handle();
int currentPriority = GetThreadPriority(hThread);
if (currentPriority != THREAD_PRIORITY_HIGHEST &&
SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST) == 0) {
OFX_LOG(ofx_error, "Error setting the thread priority");
}
#endif
return 0;
}
AVCodecContext* FFMPEGDecoder::GetAvctx() {
return avctx;
}
int FFMPEGDecoder::GetPktSerial() {
return pkt_serial;
}
int FFMPEGDecoder::GetFinished() {
return finished;
}
void FFMPEGDecoder::SetTime ( int64_t _start_pts, AVRational _start_pts_tb) {
this->start_pts = _start_pts;
this->start_pts_tb = _start_pts_tb;
}
void FFMPEGDecoder::SetFinished ( int _finished ) {
this->finished = _finished;
}