=====================================================
=====================================================
音频解码线程 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)