#include "Demuxer.h" #include "BoostLog.h" extern "C" { #include "libavformat/avformat.h" } static_assert(AVMEDIA_TYPE_VIDEO == Stream::Video, "enum value must same..."); Demuxer::Demuxer() { m_context = avformat_alloc_context(); } Demuxer::~Demuxer() { m_exit = true; if (m_thread.joinable()) m_thread.join(); } void Demuxer::open(const std::string &path) { avformat_open_input(&m_context, path.c_str(), nullptr, nullptr); av_dump_format(m_context, 0, path.c_str(), 0); const AVCodec *videoCodec = nullptr, *audioCodec = nullptr; m_streams[Stream::Video] = av_find_best_stream(m_context, AVMEDIA_TYPE_VIDEO, -1, -1, &videoCodec, 0); m_streams[Stream::Audio] = av_find_best_stream(m_context, AVMEDIA_TYPE_AUDIO, -1, -1, &audioCodec, 0); LOG(info) << "video stream index: " << m_streams[Stream::Video] << ", audio stream index: " << m_streams[Stream::Audio]; m_codecInformations[Stream::Video] = {videoCodec, m_context->streams[Stream::Video]->codecpar}; m_codecInformations[Stream::Audio] = std::pair(audioCodec, m_context->streams[Stream::Audio]->codecpar); } Demuxer::CodecInformation Demuxer::codecInformation(Stream type) const { return m_codecInformations[type]; } void Demuxer::setStreamPacketCallback(Stream type, const Callback &callback) { m_callback[type] = callback; } void Demuxer::start() { m_exit = false; m_thread = std::thread(&Demuxer::run, this); } void Demuxer::run() { auto packet = av_packet_alloc(); while (!m_exit) { int ret = av_read_frame(m_context, packet); if (ret == AVERROR_EOF) { LOG(info) << "end of file."; 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; } std::shared_ptr out(av_packet_alloc(), [](AVPacket *packet) { av_packet_free(&packet); }); av_packet_ref(out.get(), packet); if (m_callback[packet->stream_index]) m_callback[packet->stream_index](out); // LOG(info) << ". " << packet->stream_index; av_packet_unref(packet); } av_packet_free(&packet); }