ffplay源码分析03 ---- 音频解码线程

=====================================================

ffplay源码分析01 ---- 框架

ffplay源码分析02 ---- 数据读取线程

ffplay源码分析03 ---- 视频解码线程

ffplay源码分析03 ---- 音频解码线程

ffplay源码分析04 ---- 音频输出

ffplay源码分析05 ---- 音频重采样

ffplay源码分析06 ---- 视频输出

ffplay源码分析07 ---- 音视频同步

=====================================================

音频解码线程  audio_thread()

// 音频解码线程
static int audio_thread(void *arg)
{
    VideoState *is = arg;
    AVFrame *frame = av_frame_alloc();  // 分配解码帧
    Frame *af;

    int got_frame = 0;  // 是否读取到帧
    AVRational tb;      // timebase
    int ret = 0;

    if (!frame)
        return AVERROR(ENOMEM);

    do {
        // 1. 读取解码帧
        if ((got_frame = decoder_decode_frame(&is->auddec, frame, NULL)) < 0)
            goto the_end;

        if (got_frame) {
            tb = (AVRational){1, frame->sample_rate};   // 设置为sample_rate为timebase


                // 2. 获取可写Frame
                if (!(af = frame_queue_peek_writable(&is->sampq)))  // 获取可写帧
                    goto the_end;
                // 3. 设置Frame并放入FrameQueue
                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);
        }
    } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);
the_end:

    av_frame_free(&frame);
    return ret;
}

 解码 decoder_decode_frame()

static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
    int ret = AVERROR(EAGAIN);

    for (;;) {
        AVPacket pkt;
        // 1. 流连续情况下获取解码后的帧
        if (d->queue->serial == d->pkt_serial) { // 1.1 先判断是否是同一播放序列的数据
            do {
                if (d->queue->abort_request)
                    return -1;  // 是否请求退出
                // 1.2. 获取解码帧
                switch (d->avctx->codec_type) {
                case AVMEDIA_TYPE_VIDEO:
                    ret = avcodec_receive_frame(d->avctx, frame);
                    //printf("frame pts:%ld, dts:%ld
", frame->pts, frame->pkt_dts);
                    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(d->avctx, frame);
                    if (ret >= 0) {
                        AVRational tb = (AVRational){1, frame->sample_rate};    //
                        if (frame->pts != AV_NOPTS_VALUE) {
                            // 如果frame->pts正常则先将其从pkt_timebase转成{1, frame->sample_rate}
                            // pkt_timebase实质就是stream->time_base
                            frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb);
                        }
                        else if (d->next_pts != AV_NOPTS_VALUE) {
                            // 如果frame->pts不正常则使用上一帧更新的next_pts和next_pts_tb
                            // 转成{1, frame->sample_rate}
                            frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
                        }
                        if (frame->pts != AV_NOPTS_VALUE) {
                            // 根据当前帧的pts和nb_samples预估下一帧的pts
                            d->next_pts = frame->pts + frame->nb_samples;
                            d->next_pts_tb = tb; // 设置timebase
                        }
                    }
                    break;
                }

                // 1.3. 检查解码是否已经结束,解码结束返回0
                if (ret == AVERROR_EOF) {
                    d->finished = d->pkt_serial;
                    printf("avcodec_flush_buffers %s(%d)
", __FUNCTION__, __LINE__);
                    avcodec_flush_buffers(d->avctx);
                    return 0;
                }
                // 1.4. 正常解码返回1
                if (ret >= 0)
                    return 1;
            } while (ret != AVERROR(EAGAIN));   // 1.5 没帧可读时ret返回EAGIN,需要继续送packet
        }

        // 2 获取一个packet,如果播放序列不一致(数据不连续)则过滤掉“过时”的packet
        do {
            // 2.1 如果没有数据可读则唤醒read_thread, 实际是continue_read_thread SDL_cond
            if (d->queue->nb_packets == 0)  // 没有数据可读
                SDL_CondSignal(d->empty_queue_cond);// 通知read_thread放入packet
            // 2.2 如果还有pending的packet则使用它
            if (d->packet_pending) {
                av_packet_move_ref(&pkt, &d->pkt);
                d->packet_pending = 0;
            } else {
                // 2.3 阻塞式读取packet
                if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
                    return -1;
            }
            if(d->queue->serial != d->pkt_serial) {
                // darren自己的代码
                printf("%s(%d) discontinue:queue->serial:%d,pkt_serial:%d
",
                       __FUNCTION__, __LINE__, d->queue->serial, d->pkt_serial);
                av_packet_unref(&pkt); // fixed me? 释放要过滤的packet
            }
        } while (d->queue->serial != d->pkt_serial);// 如果不是同一播放序列(流不连续)则继续读取

        // 3 将packet送入解码器
        if (pkt.data == flush_pkt.data) {//
            // when seeking or when switching to a different stream
            avcodec_flush_buffers(d->avctx); //清空里面的缓存帧
            d->finished = 0;        // 重置为0
            d->next_pts = d->start_pts;     // 主要用在了audio
            d->next_pts_tb = d->start_pts_tb;// 主要用在了audio
        } else {
            if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
                int got_frame = 0;
                ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &pkt);
                if (ret < 0) {
                    ret = AVERROR(EAGAIN);
                } else {
                    if (got_frame && !pkt.data) {
                        d->packet_pending = 1;
                        av_packet_move_ref(&d->pkt, &pkt);
                    }
                    ret = got_frame ? 0 : (pkt.data ? AVERROR(EAGAIN) : AVERROR_EOF);
                }
            } else {
                if (avcodec_send_packet(d->avctx, &pkt) == AVERROR(EAGAIN)) {
                    av_log(d->avctx, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.
");
                    d->packet_pending = 1;
                    av_packet_move_ref(&d->pkt, &pkt);
                }
            }
            av_packet_unref(&pkt);    // 一定要自己去释放音视频数据
        }
    }
}
frame->pts的计算要转换一下时基:
frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb);

打断点看一下:tb: {1, 44100},  d->avctx->pkt_timebase:{1, 1000},frame->pts: 57, j结果:2514,其实就是把pts的时基从d->avctx->pkt_timebase转到tb,相当于两个单位之间转换。

我们看看av_rescale_q这个函数:

int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
{
    return av_rescale_q_rnd(a, bq, cq, AV_ROUND_NEAR_INF);
}

int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq,
                         enum AVRounding rnd)
{
    int64_t b = bq.num * (int64_t)cq.den; // 1000
    int64_t c = cq.num * (int64_t)bq.den; // 44100
    return av_rescale_rnd(a, b, c, rnd);
}

int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
{
    int64_t r = 0;
    av_assert2(c > 0);
    av_assert2(b >=0);
    av_assert2((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4);

    if (c <= 0 || b < 0 || !((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4))
        return INT64_MIN;

    if (rnd & AV_ROUND_PASS_MINMAX) {
        if (a == INT64_MIN || a == INT64_MAX)
            return a;
        rnd -= AV_ROUND_PASS_MINMAX;
    }

    if (a < 0)
        return -(uint64_t)av_rescale_rnd(-FFMAX(a, -INT64_MAX), b, c, rnd ^ ((rnd >> 1) & 1));

    if (rnd == AV_ROUND_NEAR_INF)
        r = c / 2;
    else if (rnd & 1)
        r = c - 1;

    if (b <= INT_MAX && c <= INT_MAX) {
        if (a <= INT_MAX)
            return (a * b + r) / c;
        else {
            int64_t ad = a / c;
            int64_t a2 = (a % c * b + r) / c;
            if (ad >= INT32_MAX && b && ad > (INT64_MAX - a2) / b)
                return INT64_MIN;
            return ad * b + a2;
        }
    } else {
#if 1
        uint64_t a0  = a & 0xFFFFFFFF;
        uint64_t a1  = a >> 32;
        uint64_t b0  = b & 0xFFFFFFFF;
        uint64_t b1  = b >> 32;
        uint64_t t1  = a0 * b1 + a1 * b0;
        uint64_t t1a = t1 << 32;
        int i;

        a0  = a0 * b0 + t1a;
        a1  = a1 * b1 + (t1 >> 32) + (a0 < t1a);
        a0 += r;
        a1 += a0 < r;

        for (i = 63; i >= 0; i--) {
            a1 += a1 + ((a0 >> i) & 1);
            t1 += t1;
            if (c <= a1) {
                a1 -= c;
                t1++;
            }
        }
        if (t1 > INT64_MAX)
            return INT64_MIN;
        return t1;
#else
        /* reference code doing (a*b + r) / c, requires libavutil/integer.h */
        AVInteger ai;
        ai = av_mul_i(av_int2i(a), av_int2i(b));
        ai = av_add_i(ai, av_int2i(r));

        return av_i2int(av_div_i(ai, av_int2i(c)));
#endif
    }
}

其实就是a*b/c,2514 = 57 * (1/1000) / (1/44100)



原文地址:https://www.cnblogs.com/vczf/p/14106721.html