#include "audio_decode_thread.h" #include "playercontroller.h" #include Q_LOGGING_CATEGORY(playerControllerAudioDecodeThread, "player.controller.AudioDecodeThread") AudioDecodeThread::AudioDecodeThread(VideoState* pState) : m_pState(pState) {} AudioDecodeThread::~AudioDecodeThread() { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] ~AudioDecodeThread, m_pState:" << (void*) m_pState; } void AudioDecodeThread::run() { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] run start, m_pState:" << (void*) m_pState; assert(m_pState); VideoState* is = m_pState; qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] VideoState* is:" << (void*) is << ", abort_request:" << is->abort_request; AVFrame* frame = av_frame_alloc(); Frame* af; #if USE_AVFILTER_AUDIO int last_serial = -1; AVChannelLayout dec_channel_layout; // int64_t int reconfigure; #endif int got_frame = 0; AVRational tb; int ret = 0; if (!frame) { qCWarning(playerControllerAudioDecodeThread) << "[AudioDecodeThread] av_frame_alloc failed!"; return; } qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] Starting decode loop"; do { if (is->abort_request) { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] abort_request set, exit."; break; } if (isExit()) { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] m_exit set, exit."; break; } qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] call decoder_decode_frame, auddec.avctx:" << (void*) is->auddec.avctx; if ((got_frame = decoder_decode_frame(&is->auddec, frame, nullptr)) < 0) { qCWarning(playerControllerAudioDecodeThread) << "[AudioDecodeThread] decoder_decode_frame failed, ret:" << got_frame; goto the_end; } if (got_frame) { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] got audio frame, pts:" << frame->pts << ", sample_rate:" << frame->sample_rate << ", nb_samples:" << frame->nb_samples << ", format:" << av_get_sample_fmt_name(AVSampleFormat(frame->format)) << ", channels:" << frame->ch_layout.nb_channels; tb = AVRational{1, frame->sample_rate}; #if USE_AVFILTER_AUDIO dec_channel_layout = frame->ch_layout; // frame->channel_layout; // reconfigure = cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.ch_layout.nb_channels, AVSampleFormat(frame->format), frame->ch_layout.nb_channels) || is->audio_filter_src.ch_layout.nb_channels != dec_channel_layout.nb_channels || is->audio_filter_src.freq != frame->sample_rate || is->auddec.pkt_serial != last_serial; if (reconfigure || is->req_afilter_reconfigure) { char buf1[1024], buf2[1024]; av_channel_layout_describe(&is->audio_filter_src.ch_layout, buf1, sizeof(buf1)); av_channel_layout_describe(&dec_channel_layout, buf2, sizeof(buf2)); av_log(nullptr, AV_LOG_DEBUG, "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s " "serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n", is->audio_filter_src.freq, is->audio_filter_src.ch_layout.nb_channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial, frame->sample_rate, frame->ch_layout.nb_channels, av_get_sample_fmt_name(AVSampleFormat(frame->format)), buf2, is->auddec.pkt_serial); is->audio_filter_src.fmt = (AVSampleFormat) frame->format; ret = av_channel_layout_copy(&is->audio_filter_src.ch_layout, &frame->ch_layout); if (ret < 0) goto the_end; is->audio_filter_src.freq = frame->sample_rate; last_serial = is->auddec.pkt_serial; ret = configure_audio_filters(is, is->afilters, 1); if (ret < 0) goto the_end; is->req_afilter_reconfigure = 0; } qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] adding frame to audio filter"; ret = av_buffersrc_add_frame(is->in_audio_filter, frame); if (ret < 0) { qCWarning(playerControllerAudioDecodeThread) << "[AudioDecodeThread] av_buffersrc_add_frame failed, ret:" << ret; goto the_end; } while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] got filtered audio frame"; tb = av_buffersink_get_time_base(is->out_audio_filter); #endif if (!(af = frame_queue_peek_writable(&is->sampq))) goto the_end; af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); af->pos = frame->pkt_pos; af->serial = is->auddec.pkt_serial; af->duration = av_q2d(AVRational{frame->nb_samples, frame->sample_rate}); qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] pushing audio frame to queue, pts:" << af->pts << ", duration:" << af->duration << ", serial:" << af->serial; av_frame_move_ref(af->frame, frame); frame_queue_push(&is->sampq); #if USE_AVFILTER_AUDIO if (is->audioq.serial != is->auddec.pkt_serial) break; } if (ret == AVERROR_EOF) { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] audio filter EOF, marking decoder finished"; is->auddec.finished = is->auddec.pkt_serial; } #endif } else { qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] no frame decoded, continue."; } } while (got_frame); the_end: #if USE_AVFILTER_AUDIO avfilter_graph_free(&is->agraph); if (is->afilters) { av_free(is->afilters); is->afilters = nullptr; } #endif av_frame_free(&frame); qCDebug(playerControllerAudioDecodeThread) << "[AudioDecodeThread] run end, abort_request:" << is->abort_request << ", m_exit:" << (m_exit ? m_exit->load() : -1) << ", total frames processed in this session"; return; }