// ***********************************************************/ // audio_decode_thread.cpp // // Copy Right @ Steven Huang. All rights reserved. // // audio decode thread // ***********************************************************/ #include "audio_decode_thread.h" #include "AVPlayer2/playercontroller.h" AudioDecodeThread::AudioDecodeThread(VideoState* pState) : m_pState(pState) {} AudioDecodeThread::~AudioDecodeThread() {} void AudioDecodeThread::stop() { *m_exit = true; m_cv.notify_all(); } void AudioDecodeThread::run() { qCDebug(playerControllerLog) << "[AudioDecodeThread] run start, m_pState:" << (void*) m_pState; assert(m_pState); VideoState* is = m_pState; qCDebug(playerControllerLog) << "[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(playerControllerLog) << "[AudioDecodeThread] av_frame_alloc failed!"; return; } do { if (is->abort_request) { qCDebug(playerControllerLog) << "[AudioDecodeThread] abort_request set, exit."; break; } if (m_exit) { qCDebug(playerControllerLog) << "[AudioDecodeThread] m_exit set, exit."; break; } qCDebug(playerControllerLog) << "[AudioDecodeThread] call decoder_decode_frame, auddec.avctx:" << (void*) is->auddec.avctx; if ((got_frame = decoder_decode_frame(&is->auddec, frame, nullptr)) < 0) { qCWarning(playerControllerLog) << "[AudioDecodeThread] decoder_decode_frame failed, ret:" << got_frame; goto the_end; } if (got_frame) { qCDebug(playerControllerLog) << "[AudioDecodeThread] got audio frame, pts:" << frame->pts << ", sample_rate:" << frame->sample_rate << ", nb_samples:" << frame->nb_samples; 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; } ret = av_buffersrc_add_frame(is->in_audio_filter, frame); if (ret < 0) goto the_end; while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) { 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}); 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) is->auddec.finished = is->auddec.pkt_serial; #endif } else { qCDebug(playerControllerLog) << "[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(playerControllerLog) << "[AudioDecodeThread] run end, abort_request:" << is->abort_request << ", m_exit:" << m_exit; return; }