zoukankan      html  css  js  c++  java
  • 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)



  • 相关阅读:
    Codeforces Round #447 Div. 2 A.B.C
    Codeforces Round #445 Div. 2 A ACM ICPC+B Vlad and Cafes
    51Nod 1035 最长的循环节 数论
    Codeforces Round #444 (Div. 2) C.Solution for Cube 模拟
    POJ 3111 K Best
    POJ 2976 Dropping tests
    POJ 3045 Cow Acrobats
    POJ 3045 Cow Acrobats
    POJ 3273
    POJ 3258 River Hopscotch
  • 原文地址:https://www.cnblogs.com/vczf/p/14106721.html
Copyright © 2011-2022 走看看