int64_t swr_next_pts(struct SwrContext *s, int64_t pts){ if(pts == INT64_MIN) return s->outpts; if (s->firstpts == AV_NOPTS_VALUE) s->outpts = s->firstpts = pts; if(s->min_compensation >= FLT_MAX) { return (s->outpts = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate)); } else { int64_t delta = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate) - s->outpts + s->drop_output*(int64_t)s->in_sample_rate; double fdelta = delta /(double)(s->in_sample_rate * (int64_t)s->out_sample_rate); if(fabs(fdelta) > s->min_compensation) { if(s->outpts == s->firstpts || fabs(fdelta) > s->min_hard_compensation){ int ret; if(delta > 0) ret = swr_inject_silence(s, delta / s->out_sample_rate); else ret = swr_drop_output (s, -delta / s-> in_sample_rate); if(ret<0){ av_log(s, AV_LOG_ERROR, "Failed to compensate for timestamp delta of %f\n", fdelta); } } else if(s->soft_compensation_duration && s->max_soft_compensation) { int duration = s->out_sample_rate * s->soft_compensation_duration; double max_soft_compensation = s->max_soft_compensation / (s->max_soft_compensation < 0 ? -s->in_sample_rate : 1); int comp = av_clipf(fdelta, -max_soft_compensation, max_soft_compensation) * duration ; av_log(s, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", fdelta, comp, duration); swr_set_compensation(s, comp, duration); } } return s->outpts; } }
static int audio_decode_frame(VideoState *is, double *pts_ptr) { int len1, len2, decoded_data_size; AVPacket *pkt = &is->audio_pkt; int got_frame = 0; int64_t dec_channel_layout; int wanted_nb_samples, resampled_data_size, n; double pts; for (;;) { while (is->audio_pkt_size > 0) { if (is->isPause == true) //判断暂停 { SDL_Delay(10); continue; } if (!is->audio_frame) { if (!(is->audio_frame = av_frame_alloc())) { return AVERROR(ENOMEM); } } else { // avcodec_get_frame_default(is->audio_frame); memset(is->audio_frame, 0, sizeof(AVFrame)); av_frame_unref(is->audio_frame); } len1 = avcodec_decode_audio4(is->audio_st->codec, is->audio_frame, &got_frame, pkt); if (len1 < 0) { // error, skip the frame is->audio_pkt_size = 0; break; } is->audio_pkt_data += len1; is->audio_pkt_size -= len1; if (!got_frame) continue; /* 计算解码出来的桢需要的缓冲大小 */ decoded_data_size = av_samples_get_buffer_size(NULL, is->audio_frame->channels, is->audio_frame->nb_samples, (AVSampleFormat)is->audio_frame->format, 1); dec_channel_layout = (is->audio_frame->channel_layout && is->audio_frame->channels == av_get_channel_layout_nb_channels( is->audio_frame->channel_layout)) ? is->audio_frame->channel_layout : av_get_default_channel_layout( is->audio_frame->channels); wanted_nb_samples = is->audio_frame->nb_samples; if (is->audio_frame->format != is->audio_src_fmt || dec_channel_layout != is->audio_src_channel_layout || is->audio_frame->sample_rate != is->audio_src_freq || (wanted_nb_samples != is->audio_frame->nb_samples && !is->swr_ctx)) { if (is->swr_ctx) swr_free(&is->swr_ctx); is->swr_ctx = swr_alloc_set_opts(NULL, is->audio_tgt_channel_layout, (AVSampleFormat)is->audio_tgt_fmt, is->audio_tgt_freq, dec_channel_layout, (AVSampleFormat)is->audio_frame->format, is->audio_frame->sample_rate, 0, NULL); if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) { //fprintf(stderr,"swr_init() failed\n"); break; } is->audio_src_channel_layout = dec_channel_layout; is->audio_src_channels = is->audio_st->codec->channels; is->audio_src_freq = is->audio_st->codec->sample_rate; is->audio_src_fmt = is->audio_st->codec->sample_fmt; } /* 这里我们可以对采样数进行调整,增加或者减少,一般可以用来做声画同步 */ if (is->swr_ctx) { const uint8_t **in = (const uint8_t **) is->audio_frame->extended_data; uint8_t *out[] = { is->audio_buf2 }; if (wanted_nb_samples != is->audio_frame->nb_samples) { if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->audio_frame->nb_samples) * is->audio_tgt_freq / is->audio_frame->sample_rate, wanted_nb_samples * is->audio_tgt_freq / is->audio_frame->sample_rate) < 0) { //fprintf(stderr,"swr_set_compensation() failed\n"); break; } } len2 = swr_convert(is->swr_ctx, out, sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt), in, is->audio_frame->nb_samples); if (len2 < 0) { //fprintf(stderr,"swr_convert() failed\n"); break; } if (len2 == sizeof(is->audio_buf2) / is->audio_tgt_channels / av_get_bytes_per_sample(is->audio_tgt_fmt)) { //fprintf(stderr,"warning: audio buffer is probably too small\n"); swr_init(is->swr_ctx); } is->audio_buf = is->audio_buf2; resampled_data_size = len2 * is->audio_tgt_channels * av_get_bytes_per_sample(is->audio_tgt_fmt); } else { resampled_data_size = decoded_data_size; is->audio_buf = is->audio_frame->data[0]; } pts = is->audio_clock; *pts_ptr = pts; n = 2 * is->audio_st->codec->channels; is->audio_clock += (double) resampled_data_size / (double) (n * is->audio_st->codec->sample_rate); if (is->seek_flag_audio) { //发生了跳转 则跳过关键帧到目的时间的这几帧 if (is->audio_clock < is->seek_time) { break; } else { is->seek_flag_audio = 0; } } // We have data, return it and come back for more later return resampled_data_size; } if (pkt->data) av_free_packet(pkt); memset(pkt, 0, sizeof(*pkt)); if (is->quit) return -1; if (is->isPause == true) //判断暂停 { SDL_Delay(10); continue; } if (packet_queue_get(&is->audioq, pkt, 0) <= 0) { return -1; } //收到这个数据 说明刚刚执行过跳转 现在需要把解码器的数据 清除一下 if(strcmp((char*)pkt->data,FLUSH_DATA) == 0) { avcodec_flush_buffers(is->audio_st->codec); av_free_packet(pkt); continue; } is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; /* if update, update the audio clock w/pts */ if (pkt->pts != AV_NOPTS_VALUE) { is->audio_clock = av_q2d(is->audio_st->time_base) * pkt->pts; } } return 0; }
int audio_decode_frame(FFmpegState *st) { int len1, len2, decoded_data_size; AVPacket *pkt = &st->audio_pkt; int got_frame = 0; int64_t dec_channel_layout; int wanted_nb_samples, resampled_data_size; for (;;) { while (st->audio_pkt_size > 0) { if (!st->aFrame) { if (!(st->aFrame = av_frame_alloc())) { return AVERROR(ENOMEM); } } //else // avcodec_get_frame_defaults(st->aFrame); len1 = avcodec_decode_audio4(st->audio_st->codec, st->aFrame, &got_frame, pkt); if (len1 < 0) { // error, skip the frame st->audio_pkt_size = 0; break; } st->audio_pkt_data += len1; st->audio_pkt_size -= len1; if (!got_frame) continue; decoded_data_size = av_samples_get_buffer_size(NULL, st->aFrame->channels, st->aFrame->nb_samples, (AVSampleFormat)st->aFrame->format, 1); dec_channel_layout = (st->aFrame->channel_layout && st->aFrame->channels == av_get_channel_layout_nb_channels(st->aFrame->channel_layout)) ? st->aFrame->channel_layout : av_get_default_channel_layout(st->aFrame->channels); wanted_nb_samples = st->aFrame->nb_samples; //fprintf(stderr, "wanted_nb_samples = %d\n", wanted_nb_samples); if (st->swr) { // const uint8_t *in[] = { is->audio_frame->data[0] }; const uint8_t **in = (const uint8_t **)st->aFrame->extended_data; uint8_t *out[] = { st->audio_buf2 }; if (wanted_nb_samples != st->aFrame->nb_samples) { if (swr_set_compensation(st->swr, (wanted_nb_samples - st->aFrame->nb_samples) * st->audio_tgt_freq / st->aFrame->sample_rate, wanted_nb_samples * st->audio_tgt_freq / st->aFrame->sample_rate) < 0) { fprintf(stderr, "swr_set_compensation() failed\n"); break; } } // SWR Convert len2 = swr_convert(st->swr, out, sizeof(st->audio_buf2) / st->audio_tgt_channels / av_get_bytes_per_sample(st->audio_tgt_fmt), in, st->aFrame->nb_samples); if (len2 < 0) { fprintf(stderr, "swr_convert() failed\n"); break; } if (len2 == sizeof(st->audio_buf2) / st->audio_tgt_channels / av_get_bytes_per_sample(st->audio_tgt_fmt)) { fprintf(stderr, "warning: audio buffer is probably too small\n"); swr_init(st->swr); } st->audio_buf = st->audio_buf2; resampled_data_size = len2 * st->audio_tgt_channels * av_get_bytes_per_sample(st->audio_tgt_fmt); } else { resampled_data_size = decoded_data_size; st->audio_buf = st->aFrame->data[0]; } // Update the wave buffer if (st->wave) { update_wave_buffer(st->audio_buf, resampled_data_size); } // We have data, return it and come back for more later return resampled_data_size; } // Read packet from queue if (pkt->data) av_free_packet(pkt); memset(pkt, 0, sizeof(*pkt)); if (st->quit) return -1; if (packet_queue_get(&st->audioq, pkt, 1) < 0) return -1; st->audio_pkt_data = pkt->data; st->audio_pkt_size = pkt->size; } }