#include "VideoDecoder.h" #include "BoostLog.h" extern "C" { #include "libavcodec/avcodec.h" } VideoDecoder::VideoDecoder(const AVCodec *codec, const AVCodecParameters *parameters) { m_context = avcodec_alloc_context3(codec); avcodec_parameters_to_context(m_context, parameters); avcodec_open2(m_context, codec, nullptr); } void VideoDecoder::start() { m_exit = false; m_thread = std::thread(&VideoDecoder::run, this); } void VideoDecoder::push(const std::shared_ptr &packet) { std::lock_guard locker(m_mutex); LOG(info) << "dts: " << packet->dts << ", pts: " << packet->pts; m_packets.push(packet); } void VideoDecoder::run() { using namespace std::chrono_literals; auto frame = av_frame_alloc(); while (!m_exit) { m_mutex.lock(); if (m_packets.empty()) { m_mutex.unlock(); std::this_thread::sleep_for(5ms); continue; } auto packet = m_packets.front(); m_packets.pop(); m_mutex.unlock(); auto ret = avcodec_send_packet(m_context, packet.get()); if (ret < 0) { char buffer[AV_ERROR_MAX_STRING_SIZE] = {0}; av_strerror(ret, buffer, sizeof(buffer)); LOG(error) << "read failed: " << ret << ", " << buffer; } while (true) { ret = avcodec_receive_frame(m_context, frame); if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) { break; } else if (ret < 0) { char buffer[AV_ERROR_MAX_STRING_SIZE] = {0}; av_strerror(ret, buffer, sizeof(buffer)); LOG(error) << "read failed: " << ret << ", " << buffer; break; } LOG(info) << "width: " << frame->width << ", height: " << frame->height << ", pts: " << frame->pts << ", pkt_dts:" << frame->pkt_dts; av_frame_unref(frame); } } av_frame_free(&frame); }