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; } }
int AudioController::filter(af_instance *af, mp_audio *data, int /*flags*/) { auto ac = priv(af); auto d = ac->d; d->af->delay = 0.0; Q_ASSERT(d->mixer != nullptr); if (d->dirty) { if (d->dirty & Amp) d->mixer->setAmp(d->amp); if (d->dirty & Normalizer) d->mixer->setNormalizer(d->normalizerActivated, d->normalizerOption); if (d->dirty & ChMap) d->mixer->setChannelLayoutMap(d->map); if (d->dirty & Scale) d->mixer->setScaler(d->tempoScalerActivated, d->scale); d->dirty = 0; } const mp_audio *in = data; if (d->resample) { const int frames_delay = swr_get_delay(d->swr, data->rate); const int frames = av_rescale_rnd(frames_delay + data->samples, d->resampled->rate, data->rate, AV_ROUND_UP); mp_audio_realloc_min(d->resampled, frames); d->af->delay = (double)frames/data->rate; if ((d->resampled->samples = frames)) d->resampled->samples = swr_convert(d->swr, (uchar**)d->resampled->planes, d->resampled->samples, (const uchar**)data->planes, data->samples); in = d->resampled; } d->mixer->apply(in); *data = *d->af->data; af->delay += d->mixer->delay(); return 0; }
/* * encode one audio frame and send it to the muxer * return 1 when encoding is finished, 0 otherwise */ static int write_audio_frame(AVFormatContext *oc, OutputStream *ost) { AVCodecContext *c; AVPacket pkt = { 0 }; // data and size must be 0; AVFrame *frame; int ret; int got_packet; int dst_nb_samples; av_init_packet(&pkt); c = ost->st->codec; frame = get_audio_frame(ost); if (frame) { /* convert samples from native format to destination codec format, using the resampler */ /* compute destination number of samples */ dst_nb_samples = av_rescale_rnd(swr_get_delay(ost->swr_ctx, c->sample_rate) + frame->nb_samples, c->sample_rate, c->sample_rate, AV_ROUND_UP); av_assert0(dst_nb_samples == frame->nb_samples); /* when we pass a frame to the encoder, it may keep a reference to it * internally; * make sure we do not overwrite it here */ ret = av_frame_make_writable(ost->frame); if (ret < 0) exit(1); /* convert to destination format */ ret = swr_convert(ost->swr_ctx, ost->frame->data, dst_nb_samples, (const uint8_t **)frame->data, frame->nb_samples); if (ret < 0) { fprintf(stderr, "Error while converting\n"); exit(1); } frame = ost->frame; frame->pts = av_rescale_q(ost->samples_count, (AVRational){1, c->sample_rate}, c->time_base); ost->samples_count += dst_nb_samples; } ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet); if (ret < 0) { fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret)); exit(1); } if (got_packet) { ret = write_frame(oc, &c->time_base, ost->st, &pkt); if (ret < 0) { fprintf(stderr, "Error while writing audio frame: %s\n", av_err2str(ret)); exit(1); } } return (frame || got_packet) ? 0 : 1; }
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readFromReadyFrame(QByteArray &result, int64 &samplesAdded) { int res = 0; if (_dstSamplesData) { // convert needed int64_t dstSamples = av_rescale_rnd(swr_get_delay(_swrContext, _srcRate) + _frame->nb_samples, _dstRate, _srcRate, AV_ROUND_UP); if (dstSamples > _maxResampleSamples) { _maxResampleSamples = dstSamples; av_free(_dstSamplesData[0]); if ((res = av_samples_alloc(_dstSamplesData, 0, AudioToChannels, _maxResampleSamples, AudioToFormat, 1)) < 0) { _dstSamplesData[0] = 0; char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return ReadResult::Error; } } if ((res = swr_convert(_swrContext, _dstSamplesData, dstSamples, (const uint8_t**)_frame->extended_data, _frame->nb_samples)) < 0) { char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return ReadResult::Error; } int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1); result.append((const char*)_dstSamplesData[0], resultLen); samplesAdded += resultLen / _sampleSize; } else { result.append((const char*)_frame->extended_data[0], _frame->nb_samples * _sampleSize); samplesAdded += _frame->nb_samples; } return ReadResult::Ok; }
static int get_out_samples(struct af_resample *s, int in_samples) { #if LIBSWRESAMPLE_VERSION_MAJOR > 1 || LIBSWRESAMPLE_VERSION_MINOR >= 2 return swr_get_out_samples(s->avrctx, in_samples); #else return av_rescale_rnd(in_samples, s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP) + swr_get_delay(s->avrctx, s->ctx.out_rate); #endif }
boost::int64_t AudioResampleImpl::resultSamples(boost::int64_t sourceSamples) const { if (!m_resampler) return 0; return av_rescale_rnd( swr_get_delay(m_resampler.get(), m_from.sampleRate()) + sourceSamples, m_to.sampleRate(), m_from.sampleRate(), AV_ROUND_UP); }
static int WriteAudioFrame(AVFormatContext *oc, OutputStream *ost, AVI6 *avi) { AVCodecContext *c = NULL; AVPacket pkt = { 0 }; AVFrame *frame = NULL; int ret = 0; int got_packet = 0; int dst_nb_samples = 0; av_init_packet(&pkt); c = ost->st->codec; frame = GetAudioFrame(ost, avi); if (frame) { // フォーマット変換後のサンプル数を決定 dst_nb_samples = av_rescale_rnd(swr_get_delay(ost->swr_ctx, frame->sample_rate) + frame->nb_samples, c->sample_rate, c->sample_rate, AV_ROUND_UP); //av_assert0(dst_nb_samples == frame->nb_samples); // フレームを書き込み可能にする ret = av_frame_make_writable(ost->frame); if (ret < 0) exit(1); // 音声フォーマットを変換 ret = swr_convert(ost->swr_ctx, ost->frame->data, dst_nb_samples, (const uint8_t **)frame->data, frame->nb_samples); if (ret < 0) { fprintf(stderr, "Error while converting\n"); return 0; } frame = ost->frame; frame->pts = av_rescale_q(ost->samples_count, (AVRational){1, c->sample_rate}, c->time_base); ost->samples_count += dst_nb_samples; ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet); if (ret < 0) { fprintf(stderr, "Error encoding audio frame: %s\n", MakeErrorString(ret)); return 0; } if (got_packet) { ret = WriteFrame(oc, &c->time_base, ost->st, &pkt); if (ret < 0) { fprintf(stderr, "Error while writing audio frame: %s\n", MakeErrorString(ret)); return 0; } } } return (frame || got_packet) ? 0 : 1; }
int MpegLoader::readMore(QByteArray &result, qint64 &samplesAdded) { int res; if ((res = av_read_frame(FmtContext_, &Avpkt_)) < 0) return -1; if (Avpkt_.stream_index == StreamId_) { av_frame_unref(Frame_); int got_frame = 0; if ((res = avcodec_decode_audio4(CodecContext_, Frame_, &got_frame, &Avpkt_)) < 0) { av_packet_unref(&Avpkt_); if (res == AVERROR_INVALIDDATA) return 0; return -1; } if (got_frame) { if (OutSamplesData_) { int64_t dstSamples = av_rescale_rnd(swr_get_delay(SwrContext_, SrcRate_) + Frame_->nb_samples, DstRate_, SrcRate_, AV_ROUND_UP); if (dstSamples > MaxResampleSamples_) { MaxResampleSamples_ = dstSamples; av_free(OutSamplesData_[0]); if ((res = av_samples_alloc(OutSamplesData_, 0, OutChannels, MaxResampleSamples_, OutFormat, 1)) < 0) { OutSamplesData_[0] = 0; av_packet_unref(&Avpkt_); return -1; } } if ((res = swr_convert(SwrContext_, OutSamplesData_, dstSamples, (const uint8_t**)Frame_->extended_data, Frame_->nb_samples)) < 0) { av_packet_unref(&Avpkt_); return -1; } qint32 resultLen = av_samples_get_buffer_size(0, OutChannels, res, OutFormat, 1); result.append((const char*)OutSamplesData_[0], resultLen); samplesAdded += resultLen / SampleSize_; } else { result.append((const char*)Frame_->extended_data[0], Frame_->nb_samples * SampleSize_); samplesAdded += Frame_->nb_samples; } } } av_packet_unref(&Avpkt_); return 1; }
static int ffmpeg_decode(struct ffmpeg_file *file) { if (file->pkt_decoded >= file->pkt->size) { int e = av_read_frame(file->format, file->pkt); if (e < 0) { return e; } file->pkt_decoded = 0; } int got_frame = 0; int e = avcodec_decode_audio4(file->codec, file->frame, &got_frame, file->pkt); if (e < 0) { return e; } if (!got_frame) { return 0; } file->pkt_decoded += e; AVFrame *frame = file->frame; int delay_nsamples = swr_get_delay(file->swr, file->codec->sample_rate); int dst_nsamples = av_rescale_rnd(delay_nsamples + frame->nb_samples, file->sample_rate, file->codec->sample_rate, AV_ROUND_UP); if (file->buf_nsamples < dst_nsamples) { if (file->buf) { av_freep(&file->buf[0]); } av_freep(&file->buf); int e = av_samples_alloc_array_and_samples(&file->buf, NULL, file->channels, file->sample_rate, file->sample_fmt, 0); if (e < 0) { return e; } file->buf_nsamples = dst_nsamples; } int ns = swr_convert(file->swr, file->buf, dst_nsamples, (const uint8_t**) frame->data, frame->nb_samples); int nb = av_samples_get_buffer_size(NULL, file->channels, ns, file->sample_fmt, 1); if (nb < 0) { return nb; } file->buf_len = nb; file->buf_offset = 0; if (file->frame->pts > 0) { file->time = file->frame->pts; } return nb; }
BOOL CVideoLivRecord::write_audio_frame(AVStream *st, void* pBuffer, LONG len) { AVCodecContext* avcc = st->codec; AVPacket pkt = {0}; av_init_packet(&pkt); AVFrame* frame = get_audio_frame(st, pBuffer, len); int ret = 0; int dst_nb_samples = 0; if (frame){ dst_nb_samples = (int)av_rescale_rnd(swr_get_delay(m_pAudioSwrctx, avcc->sample_rate) + frame->nb_samples, avcc->sample_rate, avcc->sample_rate, AV_ROUND_UP); av_assert0(dst_nb_samples == frame->nb_samples); ret = av_frame_make_writable(m_pAudioFrame); if (ret < 0){ log("[CVideoLivRecord::write_audio_frame] -- av_frame_make_writable() error"); return FALSE; } ret = swr_convert(m_pAudioSwrctx, m_pAudioFrame->data, dst_nb_samples, (const uint8_t**)frame->data, frame->nb_samples); if (ret < 0){ log("[CVideoLivRecord::write_audio_frame] -- av_frame_make_writable() error"); return FALSE; } frame = m_pAudioFrame; AVRational tmp = {1, avcc->sample_rate}; frame->pts = av_rescale_q(m_AudioSamplesCount, tmp, avcc->time_base); m_AudioSamplesCount += dst_nb_samples; } int got_packet = 0; ret = avcodec_encode_audio2(avcc, &pkt, frame, &got_packet); if (ret < 0){ log("[CVideoLivRecord::write_audio_frame] -- avcodec_encode_audio2() error"); return FALSE; } if(got_packet){ av_packet_rescale_ts(&pkt, avcc->time_base, st->time_base); pkt.stream_index = st->index; ret = av_interleaved_write_frame(m_pAVFormatContext, &pkt); //ret = write_audio_frame(m_pAudioStream, pBuffer, len); if (ret < 0){ log("[CVideoLivRecord::write_audio_frame] -- write_audio_frame() error"); return FALSE; } } return (frame || got_packet)? FALSE : TRUE; }
int create_channel_data( AVFrame *pFrame ) { //printf( "In Create Channel data : Thread 1\n" ); int dst_nb_channels = av_get_channel_layout_nb_channels ( AV_CH_LAYOUT_STEREO ); int dst_linesize; int delay = swr_get_delay( gMedia->pSwrContext, pFrame->sample_rate ); int dst_nb_samples = av_rescale_rnd( pFrame->nb_samples + delay, pFrame->sample_rate, pFrame->sample_rate, AV_ROUND_UP ); //printf("Destination channels = %d\n",dst_nb_channels); //printf("Destination samples = %d\n",dst_nb_samples); int error_check = av_samples_alloc_array_and_samples ( &gMedia->audio_buf, &dst_linesize, dst_nb_channels, dst_nb_samples, AV_SAMPLE_FMT_FLT, 1 ); if ( error_check < 0 ) { fprintf( stderr, "Could not allocate destination samples\n" ); } int data_size = av_samples_get_buffer_size ( NULL, pFrame->channels, pFrame->nb_samples, pFrame->format, 0 ); /* printf("Number of samples = %d\n",pFrame->nb_samples); printf("Number of bytes = %d\n",pFrame->nb_samples*2*4); printf("Linesize per channel is %d\n",pFrame->linesize[0]); printf("Calculated datasize is %d\n",data_size); */ swr_convert( gMedia->pSwrContext, ( uint8_t ** )( gMedia->audio_buf ) , pFrame->nb_samples, ( const uint8_t ** )pFrame->data, pFrame->nb_samples ); return data_size; }
int submitAudioFrame(char *data, int length, long frameTimestamp) { AVPacket pkt; int ret; AVFrame *frame; int got_packet; int sampleCount; // If no stream header has been written yet, don't do anything if (hasWrittenStreamHeader == 0) { return 0; } frame = avcodec_alloc_frame(); if (frame == NULL) { fprintf(stderr, "Failed to allocate frame\n"); return -1; } av_init_packet(&pkt); // Copy our data in memcpy(srcSamplesData[0], data, length); srcSamplesCount = length / 4; // Resample to floating point sampleCount = av_rescale_rnd(swr_get_delay(swrContext, audioCodecCtx->sample_rate) + srcSamplesCount, audioCodecCtx->sample_rate, audioCodecCtx->sample_rate, AV_ROUND_UP); if (sampleCount > maxDstSamplesCount) { // Need to resize the buffer av_free(dstSamplesData[0]); ret = av_samples_alloc(dstSamplesData, &dstSamplesLinesize, audioCodecCtx->channels, sampleCount, audioCodecCtx->sample_fmt, 0); if (ret < 0) { fprintf(stderr, "av_samples_alloc() failed: %d\n", ret); return ret; } maxDstSamplesCount = sampleCount; dstSamplesSize = av_samples_get_buffer_size(NULL, audioCodecCtx->channels, sampleCount, audioCodecCtx->sample_fmt, 0); } ret = swr_convert(swrContext, dstSamplesData, sampleCount, (const unsigned char **)srcSamplesData, srcSamplesCount); if (ret < 0) { fprintf(stderr, "swr_convert() failed: %d\n", ret); return ret; } frame->nb_samples = sampleCount; ret = avcodec_fill_audio_frame(frame, audioCodecCtx->channels, audioCodecCtx->sample_fmt, dstSamplesData[0], dstSamplesSize, 0); if (ret < 0) { fprintf(stderr, "avcodec_fill_audio_frame() failed: %d\n", ret); avcodec_free_frame(&frame); return ret; } // pkt is freed on failure or !got_packet pkt.data = NULL; pkt.size = 0; ret = avcodec_encode_audio2(audioCodecCtx, &pkt, frame, &got_packet); if (ret < 0) { fprintf(stderr, "avcodec_encode_audio2() failed: %d\n", ret); avcodec_free_frame(&frame); return ret; } if (!got_packet) { // Nothing to do here return 0; } pkt.stream_index = audioStream->index; pkt.pts = frameTimestamp; pthread_mutex_lock(&streamLock); ret = av_interleaved_write_frame(formatContext, &pkt); pthread_mutex_unlock(&streamLock); avcodec_free_frame(&frame); av_free_packet(&pkt); if (ret != 0) { fprintf(stderr, "av_interleaved_write_frame() failed: %d\n", ret); return ret; } return 0; }
status_t FFMPEGer::encodeAudio(MediaBuffer* src, MediaBuffer* dst){ AVCodecContext *c; AVFrame *frame = NULL; int ret; int got_packet; int dst_nb_samples; OutputStream* ost = &audio_st; unsigned char* srcData = (unsigned char*)src->data() + src->range_offset(); int copySize = getAudioEncodeBufferSize(); while(srcData < ((unsigned char*)src->data() + src->range_offset() + src->range_length())){ AVPacket pkt = { 0 }; // data and size must be 0; av_init_packet(&pkt); c = ost->st->codec; frame = audio_st.tmp_frame; memcpy(frame->data[0], srcData, copySize); srcData += copySize; frame->pts = audio_st.next_pts; audio_st.next_pts += frame->nb_samples; if (frame) { /* convert samples from native format to destination codec format, using the resampler */ /* compute destination number of samples */ dst_nb_samples = av_rescale_rnd(swr_get_delay(ost->swr_ctx, c->sample_rate) + frame->nb_samples, c->sample_rate, c->sample_rate, AV_ROUND_UP); av_assert0(dst_nb_samples == frame->nb_samples); /* when we pass a frame to the encoder, it may keep a reference to it * internally; * make sure we do not overwrite it here */ ret = av_frame_make_writable(ost->frame); if (ret < 0) return UNKNOWN_ERROR; /* convert to destination format */ ret = swr_convert(ost->swr_ctx, ost->frame->data, dst_nb_samples, (const uint8_t **)frame->data, frame->nb_samples); if (ret < 0) { ALOGE("Error while converting"); return UNKNOWN_ERROR; } frame = ost->frame; frame->pts = av_rescale_q(ost->samples_count, (AVRational){1, c->sample_rate}, c->time_base); ost->samples_count += dst_nb_samples; } ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet); if (ret < 0) { ALOGE("Error encoding audio frame: %s", av_err2str(ret)); return UNKNOWN_ERROR; } pkt.pts = frame->pts;// #if 0 static int count = 0; char a[50] = {0}; sprintf(a, "/sdcard/pcm%d", count++); FILE* f1 = fopen(a, "ab"); if(f1 != NULL){ size_t res = fwrite(pkt.data, 1, pkt.size, f1); fclose(f1); ALOGV("fwrite %d of %d to /sdcard/pcm!", res, pkt.size); }else ALOGE("can not fopen /sdcard/pcm!!"); #endif if (got_packet) { ret = write_frame(fmt_ctx, &c->time_base, ost->st, &pkt); if (ret < 0) { ALOGE("Error while writing audio frame: %s", av_err2str(ret)); return UNKNOWN_ERROR; } } } }
int main(int argc, char **argv) { int64_t src_ch_layout = AV_CH_LAYOUT_STEREO, dst_ch_layout = AV_CH_LAYOUT_SURROUND; int src_rate = 48000, dst_rate = 44100; uint8_t **src_data = NULL, **dst_data = NULL; int src_nb_channels = 0, dst_nb_channels = 0; int src_linesize, dst_linesize; int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples; enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_DBL, dst_sample_fmt = AV_SAMPLE_FMT_S16; const char *dst_filename = NULL; FILE *dst_file; int dst_bufsize; const char *fmt; struct SwrContext *swr_ctx; double t; int ret; if (argc != 2) { fprintf(stderr, "Usage: %s output_file\n" "API example program to show how to resample an audio stream with libswresample.\n" "This program generates a series of audio frames, resamples them to a specified " "output format and rate and saves them to an output file named output_file.\n", argv[0]); exit(1); } dst_filename = argv[1]; dst_file = fopen(dst_filename, "wb"); if (!dst_file) { fprintf(stderr, "Could not open destination file %s\n", dst_filename); exit(1); } /* create resampler context */ swr_ctx = swr_alloc(); if (!swr_ctx) { fprintf(stderr, "Could not allocate resampler context\n"); ret = AVERROR(ENOMEM); goto end; } /* set options */ av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0); av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0); av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0); av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0); /* initialize the resampling context */ if ((ret = swr_init(swr_ctx)) < 0) { fprintf(stderr, "Failed to initialize the resampling context\n"); goto end; } /* allocate source and destination samples buffers */ src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout); ret = alloc_samples_array_and_data(&src_data, &src_linesize, src_nb_channels, src_nb_samples, src_sample_fmt, 0); if (ret < 0) { fprintf(stderr, "Could not allocate source samples\n"); goto end; } /* compute the number of converted samples: buffering is avoided * ensuring that the output buffer will contain at least all the * converted input samples */ max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); /* buffer is going to be directly written to a rawaudio file, no alignment */ dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout); ret = alloc_samples_array_and_data(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, dst_sample_fmt, 0); if (ret < 0) { fprintf(stderr, "Could not allocate destination samples\n"); goto end; } t = 0; do { /* generate synthetic audio */ fill_samples((double *)src_data[0], src_nb_samples, src_nb_channels, src_rate, &t); /* compute destination number of samples */ dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); if (dst_nb_samples > max_dst_nb_samples) { av_free(dst_data[0]); ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, dst_sample_fmt, 1); if (ret < 0) break; max_dst_nb_samples = dst_nb_samples; } /* convert to destination format */ ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)src_data, src_nb_samples); if (ret < 0) { fprintf(stderr, "Error while converting\n"); goto end; } dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, ret, dst_sample_fmt, 1); printf("t:%f in:%d out:%d\n", t, src_nb_samples, ret); fwrite(dst_data[0], 1, dst_bufsize, dst_file); } while (t < 10); if ((ret = get_format_from_sample_fmt(&fmt, dst_sample_fmt) < 0)) goto end; fprintf(stderr, "Resampling succeeded. Play the output file with the command:\n" "ffplay -f %s -channel_layout %"PRId64" -channels %d -ar %d %s\n", fmt, dst_ch_layout, dst_nb_channels, dst_rate, dst_filename); end: if (dst_file) fclose(dst_file); if (src_data) av_freep(&src_data[0]); av_freep(&src_data); if (dst_data) av_freep(&dst_data[0]); av_freep(&dst_data); swr_free(&swr_ctx); return ret < 0; }
AkPacket ConvertAudioFFmpeg::convert(const AkAudioPacket &packet, const AkCaps &oCaps) { AkAudioCaps oAudioCaps(oCaps); int64_t iSampleLayout = channelLayouts->value(packet.caps().layout(), 0); AVSampleFormat iSampleFormat = av_get_sample_fmt(AkAudioCaps::sampleFormatToString(packet.caps().format()) .toStdString().c_str()); int iSampleRate = packet.caps().rate(); int iNChannels = packet.caps().channels(); int iNSamples = packet.caps().samples(); int64_t oSampleLayout = channelLayouts->value(oAudioCaps.layout(), AV_CH_LAYOUT_STEREO); AVSampleFormat oSampleFormat = av_get_sample_fmt(AkAudioCaps::sampleFormatToString(oAudioCaps.format()) .toStdString().c_str()); int oSampleRate = oAudioCaps.rate(); int oNChannels = oAudioCaps.channels(); this->m_resampleContext = swr_alloc_set_opts(this->m_resampleContext, oSampleLayout, oSampleFormat, oSampleRate, iSampleLayout, iSampleFormat, iSampleRate, 0, NULL); if (!this->m_resampleContext) return AkPacket(); // Create input audio frame. static AVFrame iFrame; memset(&iFrame, 0, sizeof(AVFrame)); iFrame.format = iSampleFormat; iFrame.channels = iNChannels; iFrame.channel_layout = uint64_t(iSampleLayout); iFrame.sample_rate = iSampleRate; iFrame.nb_samples = iNSamples; iFrame.pts = iFrame.pkt_pts = packet.pts(); if (avcodec_fill_audio_frame(&iFrame, iFrame.channels, iSampleFormat, reinterpret_cast<const uint8_t *>(packet.buffer().constData()), packet.buffer().size(), 1) < 0) { return AkPacket(); } // Fill output audio frame. AVFrame oFrame; memset(&oFrame, 0, sizeof(AVFrame)); oFrame.format = oSampleFormat; oFrame.channels = oNChannels; oFrame.channel_layout = uint64_t(oSampleLayout); oFrame.sample_rate = oSampleRate; oFrame.nb_samples = int(swr_get_delay(this->m_resampleContext, oSampleRate)) + iFrame.nb_samples * oSampleRate / iSampleRate + 3; oFrame.pts = oFrame.pkt_pts = iFrame.pts * oSampleRate / iSampleRate; // Calculate the size of the audio buffer. int frameSize = av_samples_get_buffer_size(oFrame.linesize, oFrame.channels, oFrame.nb_samples, oSampleFormat, 1); QByteArray oBuffer(frameSize, Qt::Uninitialized); if (avcodec_fill_audio_frame(&oFrame, oFrame.channels, oSampleFormat, reinterpret_cast<const uint8_t *>(oBuffer.constData()), oBuffer.size(), 1) < 0) { return AkPacket(); } // convert to destination format if (swr_convert_frame(this->m_resampleContext, &oFrame, &iFrame) < 0) return AkPacket(); frameSize = av_samples_get_buffer_size(oFrame.linesize, oFrame.channels, oFrame.nb_samples, oSampleFormat, 1); oBuffer.resize(frameSize); AkAudioPacket oAudioPacket; oAudioPacket.caps() = oAudioCaps; oAudioPacket.caps().samples() = oFrame.nb_samples; oAudioPacket.buffer() = oBuffer; oAudioPacket.pts() = oFrame.pts; oAudioPacket.timeBase() = AkFrac(1, oAudioCaps.rate()); oAudioPacket.index() = packet.index(); oAudioPacket.id() = packet.id(); return oAudioPacket.toPacket(); }
CBaseDec::RetCode CFfmpegDec::Decoder(FILE *_in, int /*OutputFd*/, State* state, CAudioMetaData* _meta_data, time_t* time_played, unsigned int* secondsToSkip) { in = _in; RetCode Status=OK; is_stream = fseek((FILE *)in, 0, SEEK_SET); if (!SetMetaData((FILE *)in, _meta_data, true)) { DeInit(); Status=DATA_ERR; return Status; } AVCodecContext *c = avc->streams[best_stream]->codec; mutex.lock(); int r = avcodec_open2(c, codec, NULL); mutex.unlock(); if (r) { DeInit(); Status=DATA_ERR; return Status; } SwrContext *swr = swr_alloc(); if (!swr) { mutex.lock(); avcodec_close(c); mutex.unlock(); DeInit(); Status=DATA_ERR; return Status; } mSampleRate = samplerate; mChannels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO); #if __BYTE_ORDER == __LITTLE_ENDIAN audioDecoder->PrepareClipPlay(mChannels, mSampleRate, 16, 1); #else audioDecoder->PrepareClipPlay(mChannels, mSampleRate, 16, 0); #endif AVFrame *frame = NULL; AVPacket rpacket; av_init_packet(&rpacket); av_opt_set_int(swr, "in_channel_layout", c->channel_layout, 0); //av_opt_set_int(swr, "out_channel_layout", c->channel_layout, 0); av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); av_opt_set_int(swr, "in_sample_rate", c->sample_rate, 0); av_opt_set_int(swr, "out_sample_rate", c->sample_rate, 0); av_opt_set_int(swr, "in_sample_fmt", c->sample_fmt, 0); av_opt_set_int(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); swr_init(swr); uint8_t *outbuf = NULL; int outsamples = 0; int outsamples_max = 0; int64_t pts = 0, start_pts = 0, next_skip_pts = 0; uint64_t skip = 0; int seek_flags = 0; do { int actSecsToSkip = *secondsToSkip; if (!is_stream && (actSecsToSkip || *state==FF || *state==REV) && avc->streams[best_stream]->time_base.num) { if (!next_skip_pts || pts >= next_skip_pts) { skip = avc->streams[best_stream]->time_base.den / avc->streams[best_stream]->time_base.num; if (actSecsToSkip) skip *= actSecsToSkip; if (*state == REV) { next_skip_pts = pts - skip; pts = next_skip_pts - skip/4; seek_flags = AVSEEK_FLAG_BACKWARD; if (pts < start_pts) { pts = start_pts; *state = PAUSE; } } else { pts += skip; next_skip_pts = pts + skip/4; seek_flags = 0; } av_seek_frame(avc, best_stream, pts, seek_flags); skip = 0; // if a custom value was set we only jump once if (actSecsToSkip != 0) { *state=PLAY; *secondsToSkip = 0; } } } while(*state==PAUSE && !is_stream) usleep(10000); if (av_read_frame(avc, &rpacket)) { Status=DATA_ERR; break; } if (rpacket.stream_index != best_stream) { av_free_packet(&rpacket); continue; } AVPacket packet = rpacket; while (packet.size > 0) { int got_frame = 0; if (!frame) { if (!(frame = avcodec_alloc_frame())) { Status=DATA_ERR; break; } } else avcodec_get_frame_defaults(frame); int len = avcodec_decode_audio4(c, frame, &got_frame, &packet); if (len < 0) { // skip frame packet.size = 0; avcodec_flush_buffers(c); mutex.lock(); avcodec_close(c); avcodec_open2(c, codec, NULL); mutex.unlock(); continue; } if (got_frame && *state!=PAUSE) { int out_samples; outsamples = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + frame->nb_samples, c->sample_rate, c->sample_rate, AV_ROUND_UP); if (outsamples > outsamples_max) { av_free(outbuf); if (av_samples_alloc(&outbuf, &out_samples, mChannels, //c->channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1) < 0) { Status=WRITE_ERR; packet.size = 0; break; } outsamples_max = outsamples; } outsamples = swr_convert(swr, &outbuf, outsamples, (const uint8_t **) &frame->data[0], frame->nb_samples); int outbuf_size = av_samples_get_buffer_size(&out_samples, mChannels, //c->channels, outsamples, AV_SAMPLE_FMT_S16, 1); if(audioDecoder->WriteClip((unsigned char*) outbuf, outbuf_size) != outbuf_size) { fprintf(stderr,"%s: PCM write error (%s).\n", ProgName, strerror(errno)); Status=WRITE_ERR; } pts = av_frame_get_best_effort_timestamp(frame); if (!start_pts) start_pts = pts; } packet.size -= len; packet.data += len; } if (time_played && avc->streams[best_stream]->time_base.den) *time_played = (pts - start_pts) * avc->streams[best_stream]->time_base.num / avc->streams[best_stream]->time_base.den; av_free_packet(&rpacket); } while (*state!=STOP_REQ && Status==OK); audioDecoder->StopClip(); meta_data_valid = false; swr_free(&swr); av_free(outbuf); av_free_packet(&rpacket); avcodec_free_frame(&frame); avcodec_close(c); //av_free(avcc); DeInit(); if (_meta_data->cover_temporary && !_meta_data->cover.empty()) { _meta_data->cover_temporary = false; unlink(_meta_data->cover.c_str()); } return Status; }
static void write_audio_frame(AVFormatContext *oc, AVStream *st) { AVCodecContext *c; AVPacket pkt = { 0 }; // data and size must be 0; int got_packet, ret, dst_nb_samples; av_init_packet(&pkt); c = st->codec; get_audio_frame((int16_t *)src_samples_data[0], src_nb_samples, c->channels); /* convert samples from native format to destination codec format, using the resampler */ if (swr_ctx) { /* compute destination number of samples */ dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, c->sample_rate) + src_nb_samples, c->sample_rate, c->sample_rate, AV_ROUND_UP); if (dst_nb_samples > max_dst_nb_samples) { av_free(dst_samples_data[0]); ret = av_samples_alloc(dst_samples_data, &dst_samples_linesize, c->channels, dst_nb_samples, c->sample_fmt, 0); if (ret < 0) exit(1); max_dst_nb_samples = dst_nb_samples; dst_samples_size = av_samples_get_buffer_size(NULL, c->channels, dst_nb_samples, c->sample_fmt, 0); } /* convert to destination format */ ret = swr_convert(swr_ctx, dst_samples_data, dst_nb_samples, (const uint8_t **)src_samples_data, src_nb_samples); if (ret < 0) { fprintf(stderr, "Error while converting\n"); exit(1); } } else { dst_nb_samples = src_nb_samples; } audio_frame->nb_samples = dst_nb_samples; audio_frame->pts = av_rescale_q(samples_count, (AVRational){1, c->sample_rate}, c->time_base); avcodec_fill_audio_frame(audio_frame, c->channels, c->sample_fmt, dst_samples_data[0], dst_samples_size, 0); samples_count += dst_nb_samples; ret = avcodec_encode_audio2(c, &pkt, audio_frame, &got_packet); if (ret < 0) { fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret)); exit(1); } if (!got_packet) return; /* rescale output packet timestamp values from codec to stream timebase */ pkt.pts = av_rescale_q_rnd(pkt.pts, c->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); pkt.dts = av_rescale_q_rnd(pkt.dts, c->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); pkt.duration = av_rescale_q(pkt.duration, c->time_base, st->time_base); pkt.stream_index = st->index; /* Write the compressed frame to the media file. */ ret = av_interleaved_write_frame(oc, &pkt); if (ret != 0) { fprintf(stderr, "Error while writing audio frame: %s\n", av_err2str(ret)); exit(1); } }
void ACapsConvertElement::iStream(const QbPacket &packet) { if (!packet.caps().isValid() || packet.caps().mimeType() != "audio/x-raw" || this->state() != ElementStatePlaying) return; // Input Format AVSampleFormat iSampleFormat = av_get_sample_fmt(packet.caps().property("format").toString().toStdString().c_str()); int iNChannels = packet.caps().property("channels").toInt(); int64_t iChannelLayout = av_get_channel_layout(packet.caps().property("layout").toString().toStdString().c_str()); int iNPlanes = av_sample_fmt_is_planar(iSampleFormat)? iNChannels: 1; int iSampleRate = packet.caps().property("rate").toInt(); int iNSamples = packet.caps().property("samples").toInt(); if (iNSamples < 1) iNSamples = 1024; bool sameMimeType = packet.caps().mimeType() == this->m_caps.mimeType(); // Output Format AVSampleFormat oSampleFormat = (sameMimeType && this->m_caps.dynamicPropertyNames().contains("format"))? av_get_sample_fmt(this->m_caps.property("format").toString().toStdString().c_str()): iSampleFormat; int oNChannels = (sameMimeType && this->m_caps.dynamicPropertyNames().contains("channels"))? this->m_caps.property("channels").toInt(): iNChannels; int64_t oChannelLayout = (sameMimeType && this->m_caps.dynamicPropertyNames().contains("layout"))? av_get_channel_layout(this->m_caps.property("layout").toString().toStdString().c_str()): iChannelLayout; int oSampleRate = (sameMimeType && this->m_caps.dynamicPropertyNames().contains("rate"))? this->m_caps.property("rate").toInt(): iSampleRate; QVector<uint8_t *> iData(iNPlanes); int iLineSize; if (av_samples_fill_arrays(&iData.data()[0], &iLineSize, (const uint8_t *) packet.buffer().data(), iNChannels, iNSamples, iSampleFormat, 1) < 0) return; QbCaps caps1(packet.caps()); QbCaps caps2(this->m_curInputCaps); caps1.setProperty("samples", QVariant()); caps2.setProperty("samples", QVariant()); if (caps1 != caps2) { // create resampler context this->m_resampleContext = SwrContextPtr(swr_alloc(), this->deleteSwrContext); if (!this->m_resampleContext) return; // set options av_opt_set_int(this->m_resampleContext.data(), "in_channel_layout", iChannelLayout, 0); av_opt_set_int(this->m_resampleContext.data(), "in_sample_rate", iSampleRate, 0); av_opt_set_sample_fmt(this->m_resampleContext.data(), "in_sample_fmt", iSampleFormat, 0); av_opt_set_int(this->m_resampleContext.data(), "out_channel_layout", oChannelLayout, 0); av_opt_set_int(this->m_resampleContext.data(), "out_sample_rate", oSampleRate, 0); av_opt_set_sample_fmt(this->m_resampleContext.data(), "out_sample_fmt", oSampleFormat, 0); // initialize the resampling context if (swr_init(this->m_resampleContext.data()) < 0) return; this->m_curInputCaps = packet.caps(); } // compute destination number of samples int oNSamples = av_rescale_rnd(swr_get_delay(this->m_resampleContext.data(), iSampleRate) + iNSamples, oSampleRate, iSampleRate, AV_ROUND_UP); // buffer is going to be directly written to a rawaudio file, no alignment int oNPlanes = av_sample_fmt_is_planar(oSampleFormat)? oNChannels: 1; QVector<uint8_t *> oData(oNPlanes); int oLineSize; int oBufferSize = av_samples_get_buffer_size(&oLineSize, oNChannels, oNSamples, oSampleFormat, 1); QSharedPointer<uchar> oBuffer(new uchar[oBufferSize]); if (!oBuffer) return; if (av_samples_fill_arrays(&oData.data()[0], &oLineSize, (const uint8_t *) oBuffer.data(), oNChannels, oNSamples, oSampleFormat, 1) < 0) return; // convert to destination format if (swr_convert(this->m_resampleContext.data(), oData.data(), oNSamples, (const uint8_t **) iData.data(), iNSamples) < 0) return; const char *format = av_get_sample_fmt_name(oSampleFormat); char layout[256]; av_get_channel_layout_string(layout, sizeof(layout), oNChannels, oChannelLayout); QString caps = QString("audio/x-raw," "format=%1," "channels=%2," "rate=%3," "layout=%4," "samples=%5").arg(format) .arg(oNChannels) .arg(oSampleRate) .arg(layout) .arg(oNSamples); QbPacket oPacket(caps, oBuffer, oBufferSize); oPacket.setPts(packet.pts()); oPacket.setDuration(packet.duration()); oPacket.setTimeBase(packet.timeBase()); oPacket.setIndex(packet.index()); emit this->oStream(oPacket); }
/** * Decode a frame to a packet, run the result through SwrContext, if desired, encode it via an appropriate * encoder, and write the results to the Java-side native buffer. * * @param aio FFAudio context * @param cached true or false * @return number of bytes placed into java buffer or a negative value, if something went wrong */ static int decode_packet(FFAudioIO *aio, int cached) { int res = 0; uint8_t **resample_buf = NULL; jobject byte_buffer = NULL; uint8_t *javaBuffer = NULL; uint32_t out_buf_size = 0; int out_buf_samples = 0; int64_t out_channel_count; int64_t out_sample_rate; int flush = aio->got_frame; enum AVSampleFormat out; int bytesConsumed = 0; init_ids(aio->env, aio->java_instance); av_opt_get_int(aio->swr_context, "out_channel_count", 0, &out_channel_count); av_opt_get_int(aio->swr_context, "out_sample_rate", 0, &out_sample_rate); av_opt_get_sample_fmt(aio->swr_context, "out_sample_fmt", 0, &out); resample_buf = av_mallocz(sizeof(uint8_t *) * 1); // one plane! // make sure we really have an audio packet if (aio->decode_packet.stream_index == aio->stream_index) { // decode frame // got_frame indicates whether we got a frame bytesConsumed = avcodec_decode_audio4(aio->decode_context, aio->decode_frame, &aio->got_frame, &aio->decode_packet); if (bytesConsumed < 0) { throwUnsupportedAudioFileExceptionIfError(aio->env, bytesConsumed, "Failed to decode audio frame."); return bytesConsumed; } if (aio->got_frame) { aio->decoded_samples += aio->decode_frame->nb_samples; out_buf_samples = aio->decode_frame->nb_samples; #ifdef DEBUG fprintf(stderr, "samples%s n:%" PRIu64 " nb_samples:%d pts:%s\n", cached ? "(cached)" : "", aio->decoded_samples, aio->decode_frame->nb_samples, av_ts2timestr(aio->decode_frame->pts, &aio->decode_context->time_base)); #endif // adjust out sample number for a different sample rate // this is an estimate!! out_buf_samples = av_rescale_rnd( swr_get_delay(aio->swr_context, aio->stream->codecpar->sample_rate) + aio->decode_frame->nb_samples, out_sample_rate, aio->stream->codecpar->sample_rate, AV_ROUND_UP ); // allocate new aio->audio_data buffers res = av_samples_alloc(aio->audio_data, NULL, av_frame_get_channels(aio->decode_frame), aio->decode_frame->nb_samples, aio->decode_frame->format, 1); if (res < 0) { throwIOExceptionIfError(aio->env, res, "Could not allocate audio buffer."); return AVERROR(ENOMEM); } // copy audio data to aio->audio_data av_samples_copy(aio->audio_data, aio->decode_frame->data, 0, 0, aio->decode_frame->nb_samples, av_frame_get_channels(aio->decode_frame), aio->decode_frame->format); res = resample(aio, resample_buf, out_buf_samples, (const uint8_t **)aio->audio_data, aio->decode_frame->nb_samples); if (res < 0) goto bail; else out_buf_samples = res; } else if (flush && swr_get_delay(aio->swr_context, aio->stream->codecpar->sample_rate)) { res = resample(aio, resample_buf, swr_get_delay(aio->swr_context, aio->stream->codecpar->sample_rate), NULL, 0); if (res < 0) goto bail; else out_buf_samples = res; } else { #ifdef DEBUG fprintf(stderr, "Got no frame.\n"); #endif } if (out_buf_samples > 0) { res = av_samples_get_buffer_size(NULL, (int)out_channel_count, out_buf_samples, out, 1); if (res < 0) goto bail; else out_buf_size = res; // ensure native buffer capacity if (aio->java_buffer_capacity < out_buf_size) { aio->java_buffer_capacity = (*aio->env)->CallIntMethod(aio->env, aio->java_instance, setNativeBufferCapacity_MID, (jint)out_buf_size); } // get java-managed byte buffer reference byte_buffer = (*aio->env)->GetObjectField(aio->env, aio->java_instance, nativeBuffer_FID); if (!byte_buffer) { res = -1; throwIOExceptionIfError(aio->env, 1, "Failed to get native buffer."); goto bail; } // we have some samples, let's copy them to the java buffer, using the desired encoding javaBuffer = (uint8_t *)(*aio->env)->GetDirectBufferAddress(aio->env, byte_buffer); if (!javaBuffer) { throwIOExceptionIfError(aio->env, 1, "Failed to get address for native buffer."); goto bail; } if (aio->encode_context) { aio->encode_frame->nb_samples = out_buf_samples; res = encode_buffer(aio, resample_buf[0], out_buf_size, javaBuffer); if (res < 0) { out_buf_size = 0; goto bail; } out_buf_size = res; } else { memcpy(javaBuffer, resample_buf[0], out_buf_size); } // we already wrote to the buffer, now we still need to // set new bytebuffer limit and position to 0. (*aio->env)->CallObjectMethod(aio->env, byte_buffer, rewind_MID); (*aio->env)->CallObjectMethod(aio->env, byte_buffer, limit_MID, out_buf_size); } } aio->resampled_samples += out_buf_size; bail: if (resample_buf) { if (resample_buf[0]) av_freep(&resample_buf[0]); av_free(resample_buf); } if (aio->audio_data[0]) av_freep(&aio->audio_data[0]); return res; }
std::int64_t Swr::GetDelay(std::int64_t base) { assert(this->context != nullptr); return swr_get_delay(this->context, base); }
static void write_audio_frame(AVFormatContext *oc, AVStream *st, int flush) { AVCodecContext *c; AVPacket pkt = { 0 }; // data and size must be 0; int got_packet, ret, dst_nb_samples; av_init_packet(&pkt); c = st->codec; if (!flush) { get_audio_frame((int16_t *)src_samples_data[0], src_nb_samples, c->channels); /* convert samples from native format to destination codec format, using the resampler */ if (swr_ctx) { /* compute destination number of samples */ dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, c->sample_rate) + src_nb_samples, c->sample_rate, c->sample_rate, AV_ROUND_UP); if (dst_nb_samples > max_dst_nb_samples) { av_free(dst_samples_data[0]); ret = av_samples_alloc(dst_samples_data, &dst_samples_linesize, c->channels, dst_nb_samples, c->sample_fmt, 0); if (ret < 0) exit(1); max_dst_nb_samples = dst_nb_samples; dst_samples_size = av_samples_get_buffer_size(NULL, c->channels, dst_nb_samples, c->sample_fmt, 0); } /* convert to destination format */ ret = swr_convert(swr_ctx, dst_samples_data, dst_nb_samples, (const uint8_t **)src_samples_data, src_nb_samples); if (ret < 0) { fprintf(stderr, "Error while converting\n"); exit(1); } } else { dst_nb_samples = src_nb_samples; } audio_frame->nb_samples = dst_nb_samples; audio_frame->pts = av_rescale_q(samples_count, (AVRational){1, c->sample_rate}, c->time_base); avcodec_fill_audio_frame(audio_frame, c->channels, c->sample_fmt, dst_samples_data[0], dst_samples_size, 0); samples_count += dst_nb_samples; } ret = avcodec_encode_audio2(c, &pkt, flush ? NULL : audio_frame, &got_packet); if (ret < 0) { fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret)); exit(1); } if (!got_packet) { if (flush) audio_is_eof = 1; return; } ret = write_frame(oc, &c->time_base, st, &pkt); if (ret < 0) { fprintf(stderr, "Error while writing audio frame: %s\n", av_err2str(ret)); exit(1); } }
static int get_delay(struct af_resample *s) { return swr_get_delay(s->avrctx, s->ctx.in_rate); }
int decode_frame_from_packet(State *state, AVPacket *aPacket, int *frame_size_ptr, int from_thread) { int n; int16_t *samples; AVPacket *pkt = aPacket; AVFrame *decoded_frame = NULL; int got_frame = 0; int64_t src_ch_layout, dst_ch_layout; int src_rate, dst_rate; uint8_t **src_data = NULL, **dst_data = NULL; int src_nb_channels = 0, dst_nb_channels = 0; int src_linesize, dst_linesize; int src_nb_samples, dst_nb_samples, max_dst_nb_samples; enum AVSampleFormat src_sample_fmt, dst_sample_fmt; int dst_bufsize; const char *fmt; struct SwrContext *swr_ctx; double t; int ret; if (aPacket->stream_index == state->audio_stream) { if (!decoded_frame) { if (!(decoded_frame = avcodec_alloc_frame())) { __android_log_print(ANDROID_LOG_INFO, "TAG", "Could not allocate audio frame\n"); return -2; } } if (avcodec_decode_audio4(state->audio_st->codec, decoded_frame, &got_frame, aPacket) < 0) { __android_log_print(ANDROID_LOG_ERROR, "TAG", "avcodec_decode_audio4() decoded no frame"); return -2; } int data_size = 0; if (got_frame) { /* if a frame has been decoded, output it */ data_size = av_samples_get_buffer_size(NULL, state->audio_st->codec->channels, decoded_frame->nb_samples, state->audio_st->codec->sample_fmt, 1); } else { *frame_size_ptr = 0; return 0; } if (decoded_frame->format != AV_SAMPLE_FMT_S16) { src_nb_samples = decoded_frame->nb_samples; src_linesize = (int) decoded_frame->linesize; src_data = decoded_frame->data; if (decoded_frame->channel_layout == 0) { decoded_frame->channel_layout = av_get_default_channel_layout(decoded_frame->channels); } /* create resampler context */ swr_ctx = swr_alloc(); if (!swr_ctx) { //fprintf(stderr, "Could not allocate resampler context\n"); //ret = AVERROR(ENOMEM); //goto end; } src_rate = decoded_frame->sample_rate; dst_rate = decoded_frame->sample_rate; src_ch_layout = decoded_frame->channel_layout; dst_ch_layout = decoded_frame->channel_layout; src_sample_fmt = decoded_frame->format; dst_sample_fmt = AV_SAMPLE_FMT_S16; av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0); av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0); av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0); av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0); /* initialize the resampling context */ if ((ret = swr_init(swr_ctx)) < 0) { __android_log_print(ANDROID_LOG_INFO, "TAG", "Failed to initialize the resampling context\n"); //goto end; } /* allocate source and destination samples buffers */ src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout); ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels, src_nb_samples, src_sample_fmt, 0); if (ret < 0) { __android_log_print(ANDROID_LOG_INFO, "TAG", "Could not allocate source samples\n"); //goto end; } /* compute the number of converted samples: buffering is avoided * ensuring that the output buffer will contain at least all the * converted input samples */ max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); /* buffer is going to be directly written to a rawaudio file, no alignment */ dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout); ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, dst_sample_fmt, 0); if (ret < 0) { __android_log_print(ANDROID_LOG_INFO, "TAG", "Could not allocate destination samples\n"); //goto end; } /* compute destination number of samples */ dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); /* convert to destination format */ ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)decoded_frame->data, src_nb_samples); if (ret < 0) { __android_log_print(ANDROID_LOG_INFO, "TAG", "Error while converting\n"); //goto end; } dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, ret, dst_sample_fmt, 1); if (dst_bufsize < 0) { fprintf(stderr, "Could not get sample buffer size\n"); //goto end; } samples = malloc(dst_bufsize); memcpy(samples, dst_data[0], dst_bufsize); data_size = dst_bufsize; swr_free(&swr_ctx); } else { /* if a frame has been decoded, output it */ data_size = av_samples_get_buffer_size(NULL, state->audio_st->codec->channels, decoded_frame->nb_samples, state->audio_st->codec->sample_fmt, 1); samples = malloc(data_size); memcpy(samples, decoded_frame->data[0], data_size); } *frame_size_ptr = data_size; // TODO add this call back! //*pts_ptr = pts; n = 2 * state->audio_st->codec->channels; state->audio_clock += (double)*frame_size_ptr / (double)(n * state->audio_st->codec->sample_rate); /* if update, update the audio clock w/pts */ if(pkt->pts != AV_NOPTS_VALUE) { state->audio_clock = av_q2d(state->audio_st->time_base) * pkt->pts; } //*frame_size_ptr = data_size; state->write_audio_callback(state->clazz, samples, data_size, from_thread); avcodec_free_frame(&decoded_frame); free(samples); return AUDIO_DATA_ID; } return 0; }
void cAudio::run() { lt_info("====================== start decoder thread ================================\n"); /* libavcodec & friends */ av_register_all(); AVCodec *codec; AVFormatContext *avfc = NULL; AVInputFormat *inp; AVFrame *frame; uint8_t *inbuf = (uint8_t *)av_malloc(INBUF_SIZE); AVPacket avpkt; int ret, driver; /* libao */ ao_info *ai; // ao_device *adevice; // ao_sample_format sformat; /* resample */ SwrContext *swr = NULL; uint8_t *obuf = NULL; int obuf_sz = 0; /* in samples */ int obuf_sz_max = 0; int o_ch, o_sr; /* output channels and sample rate */ uint64_t o_layout; /* output channels layout */ char tmp[64] = "unknown"; curr_pts = 0; av_init_packet(&avpkt); inp = av_find_input_format("mpegts"); AVIOContext *pIOCtx = avio_alloc_context(inbuf, INBUF_SIZE, // internal Buffer and its size 0, // bWriteable (1=true,0=false) NULL, // user data; will be passed to our callback functions _my_read, // read callback NULL, // write callback NULL); // seek callback avfc = avformat_alloc_context(); avfc->pb = pIOCtx; avfc->iformat = inp; avfc->probesize = 188*5; thread_started = true; if (avformat_open_input(&avfc, NULL, inp, NULL) < 0) { lt_info("%s: avformat_open_input() failed.\n", __func__); goto out; } ret = avformat_find_stream_info(avfc, NULL); lt_debug("%s: avformat_find_stream_info: %d\n", __func__, ret); if (avfc->nb_streams != 1) { lt_info("%s: nb_streams: %d, should be 1!\n", __func__, avfc->nb_streams); goto out; } if (avfc->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO) lt_info("%s: stream 0 no audio codec? 0x%x\n", __func__, avfc->streams[0]->codec->codec_type); c = avfc->streams[0]->codec; codec = avcodec_find_decoder(c->codec_id); if (!codec) { lt_info("%s: Codec for %s not found\n", __func__, avcodec_get_name(c->codec_id)); goto out; } if (avcodec_open2(c, codec, NULL) < 0) { lt_info("%s: avcodec_open2() failed\n", __func__); goto out; } frame = av_frame_alloc(); if (!frame) { lt_info("%s: avcodec_alloc_frame failed\n", __func__); goto out2; } /* output sample rate, channels, layout could be set here if necessary */ o_ch = c->channels; /* 2 */ o_sr = c->sample_rate; /* 48000 */ o_layout = c->channel_layout; /* AV_CH_LAYOUT_STEREO */ if (sformat.channels != o_ch || sformat.rate != o_sr || sformat.byte_format != AO_FMT_NATIVE || sformat.bits != 16 || adevice == NULL) { driver = ao_default_driver_id(); sformat.bits = 16; sformat.channels = o_ch; sformat.rate = o_sr; sformat.byte_format = AO_FMT_NATIVE; sformat.matrix = 0; if (adevice) ao_close(adevice); adevice = ao_open_live(driver, &sformat, NULL); ai = ao_driver_info(driver); lt_info("%s: changed params ch %d srate %d bits %d adevice %p\n", __func__, o_ch, o_sr, 16, adevice);; lt_info("libao driver: %d name '%s' short '%s' author '%s'\n", driver, ai->name, ai->short_name, ai->author); } #if 0 lt_info(" driver options:"); for (int i = 0; i < ai->option_count; ++i) fprintf(stderr, " %s", ai->options[i]); fprintf(stderr, "\n"); #endif av_get_sample_fmt_string(tmp, sizeof(tmp), c->sample_fmt); lt_info("decoding %s, sample_fmt %d (%s) sample_rate %d channels %d\n", avcodec_get_name(c->codec_id), c->sample_fmt, tmp, c->sample_rate, c->channels); swr = swr_alloc_set_opts(swr, o_layout, AV_SAMPLE_FMT_S16, o_sr, /* output */ c->channel_layout, c->sample_fmt, c->sample_rate, /* input */ 0, NULL); if (! swr) { lt_info("could not alloc resample context\n"); goto out3; } swr_init(swr); while (thread_started) { int gotframe = 0; if (av_read_frame(avfc, &avpkt) < 0) break; avcodec_decode_audio4(c, frame, &gotframe, &avpkt); if (gotframe && thread_started) { int out_linesize; obuf_sz = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + frame->nb_samples, o_sr, c->sample_rate, AV_ROUND_UP); if (obuf_sz > obuf_sz_max) { lt_info("obuf_sz: %d old: %d\n", obuf_sz, obuf_sz_max); av_free(obuf); if (av_samples_alloc(&obuf, &out_linesize, o_ch, frame->nb_samples, AV_SAMPLE_FMT_S16, 1) < 0) { lt_info("av_samples_alloc failed\n"); av_free_packet(&avpkt); break; /* while (thread_started) */ } obuf_sz_max = obuf_sz; } obuf_sz = swr_convert(swr, &obuf, obuf_sz, (const uint8_t **)frame->extended_data, frame->nb_samples); curr_pts = av_frame_get_best_effort_timestamp(frame); lt_debug("%s: pts 0x%" PRIx64 " %3f\n", __func__, curr_pts, curr_pts/90000.0); int o_buf_sz = av_samples_get_buffer_size(&out_linesize, o_ch, obuf_sz, AV_SAMPLE_FMT_S16, 1); ao_play(adevice, (char *)obuf, o_buf_sz); } av_free_packet(&avpkt); } // ao_close(adevice); /* can take long :-( */ av_free(obuf); swr_free(&swr); out3: av_frame_free(&frame); out2: avcodec_close(c); c = NULL; out: avformat_close_input(&avfc); av_free(pIOCtx->buffer); av_free(pIOCtx); lt_info("======================== end decoder thread ================================\n"); }
long audio_tutorial_resample(VideoState *is, struct AVFrame *inframe) { #ifdef __RESAMPLER__ #ifdef __LIBAVRESAMPLE__ // There is pre 1.0 libavresample and then there is above.. #if LIBAVRESAMPLE_VERSION_MAJOR == 0 void **resample_input_bytes = (void **)inframe->extended_data; #else uint8_t **resample_input_bytes = (uint8_t **)inframe->extended_data; #endif #else uint8_t **resample_input_bytes = (uint8_t **)inframe->extended_data; #endif int resample_nblen = 0; long resample_long_bytes = 0; if( is->pResampledOut == NULL || inframe->nb_samples > is->resample_size) { #if __LIBAVRESAMPLE__ is->resample_size = av_rescale_rnd(avresample_get_delay(is->pSwrCtx) + inframe->nb_samples, 44100, 44100, AV_ROUND_UP); #else is->resample_size = av_rescale_rnd(swr_get_delay(is->pSwrCtx, 44100) + inframe->nb_samples, 44100, 44100, AV_ROUND_UP); #endif if(is->pResampledOut != NULL) { av_free(is->pResampledOut); is->pResampledOut = NULL; } av_samples_alloc(&is->pResampledOut, &is->resample_lines, 2, is->resample_size, AV_SAMPLE_FMT_S16, 0); } #ifdef __LIBAVRESAMPLE__ // OLD API (0.0.3) ... still NEW API (1.0.0 and above).. very frustrating.. // USED IN FFMPEG 1.0 (LibAV SOMETHING!). New in FFMPEG 1.1 and libav 9 #if LIBAVRESAMPLE_VERSION_INT <= 3 // AVResample OLD resample_nblen = avresample_convert(is->pSwrCtx, (void **)&is->pResampledOut, 0, is->resample_size, (void **)resample_input_bytes, 0, inframe->nb_samples); #else //AVResample NEW resample_nblen = avresample_convert(is->pSwrCtx, (uint8_t **)&is->pResampledOut, 0, is->resample_size, (uint8_t **)resample_input_bytes, 0, inframe->nb_samples); #endif #else // SWResample resample_nblen = swr_convert(is->pSwrCtx, (uint8_t **)&is->pResampledOut, is->resample_size, (const uint8_t **)resample_input_bytes, inframe->nb_samples); #endif resample_long_bytes = av_samples_get_buffer_size(NULL, 2, resample_nblen, AV_SAMPLE_FMT_S16, 1); if (resample_nblen < 0) { fprintf(stderr, "reSample to another sample format failed!\n"); return -1; } return resample_long_bytes; #else return -1; #endif }
int procAudioResampling(AVCodecContext * audio_dec_ctx, AVFrame * pAudioDecodeFrame, int out_sample_fmt, int out_channels, int out_sample_rate, uint8_t * audio_chunk) { SwrContext * swr_ctx = NULL; int data_size = 0; int ret = 0; int64_t src_ch_layout = audio_dec_ctx->channel_layout; int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO; int dst_nb_channels = 0; int dst_linesize = 0; int src_nb_samples = 0; int dst_nb_samples = 0; int max_dst_nb_samples = 0; uint8_t **dst_data = NULL; int resampled_data_size = 0; swr_ctx = swr_alloc(); if (!swr_ctx) { LOGD("swr_alloc error \n"); return -1; } src_ch_layout = (audio_dec_ctx->channels == av_get_channel_layout_nb_channels(audio_dec_ctx->channel_layout)) ? audio_dec_ctx->channel_layout : av_get_default_channel_layout(audio_dec_ctx->channels); if (out_channels == 1) { dst_ch_layout = AV_CH_LAYOUT_MONO; //LOGD("dst_ch_layout: AV_CH_LAYOUT_MONO\n"); } else if (out_channels == 2) { dst_ch_layout = AV_CH_LAYOUT_STEREO; //LOGD("dst_ch_layout: AV_CH_LAYOUT_STEREO\n"); } else { dst_ch_layout = AV_CH_LAYOUT_SURROUND; //LOGD("dst_ch_layout: AV_CH_LAYOUT_SURROUND\n"); } if (src_ch_layout <= 0) { LOGD("src_ch_layout error \n"); return -1; } src_nb_samples = pAudioDecodeFrame->nb_samples; if (src_nb_samples <= 0) { LOGD("src_nb_samples error \n"); return -1; } av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(swr_ctx, "in_sample_rate", audio_dec_ctx->sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", audio_dec_ctx->sample_fmt, 0); av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(swr_ctx, "out_sample_rate", out_sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", (AVSampleFormat)out_sample_fmt, 0); if ((ret = swr_init(swr_ctx)) < 0) { LOGD("Failed to initialize the resampling context\n"); return -1; } max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, out_sample_rate, audio_dec_ctx->sample_rate, AV_ROUND_UP); if (max_dst_nb_samples <= 0) { LOGD("av_rescale_rnd error \n"); return -1; } dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout); ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, (AVSampleFormat)out_sample_fmt, 0); if (ret < 0) { LOGD("av_samples_alloc_array_and_samples error \n"); return -1; } dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, audio_dec_ctx->sample_rate) + src_nb_samples, out_sample_rate, audio_dec_ctx->sample_rate, AV_ROUND_UP); if (dst_nb_samples <= 0) { LOGD("av_rescale_rnd error \n"); return -1; } if (dst_nb_samples > max_dst_nb_samples) { av_free(dst_data[0]); ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, (AVSampleFormat)out_sample_fmt, 1); max_dst_nb_samples = dst_nb_samples; } if (swr_ctx) { ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)pAudioDecodeFrame->data, pAudioDecodeFrame->nb_samples); if (ret < 0) { LOGD("swr_convert error \n"); return -1; } resampled_data_size = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, ret, (AVSampleFormat)out_sample_fmt, 1); if (resampled_data_size < 0) { LOGD("av_samples_get_buffer_size error \n"); return -1; } } else { LOGD("swr_ctx null error \n"); return -1; } //LOGD("resampled_data_size:%d",resampled_data_size); memcpy(audio_chunk, dst_data[0], resampled_data_size); if (dst_data) { av_freep(&dst_data[0]); } av_freep(&dst_data); dst_data = NULL; if (swr_ctx) { swr_free(&swr_ctx); } return resampled_data_size; }
int audioResampling(AVCodecContext *audio_dec_ctx, AVFrame *pAudioDecodeFrame, int out_sample_fmt, int out_channels, int out_sample_rate, char *out_buf) { __android_log_print(ANDROID_LOG_DEBUG, TAG, "stream12"); SwrContext *swr_ctx = NULL; int data_size = 0; int ret = 0; int64_t src_ch_layout = AV_CH_LAYOUT_STEREO; //初始化这样根据不同文件做调整 int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO; //这里设定ok int dst_nb_channels = 0; int dst_linesize = 0; int src_nb_samples = 0; int dst_nb_samples = 0; int max_dst_nb_samples = 0; uint8_t **dst_data = NULL; int resampled_data_size = 0; //重新采样 if (swr_ctx) { swr_free(&swr_ctx); } swr_ctx = swr_alloc(); __android_log_print(ANDROID_LOG_DEBUG, TAG, "stream12-1"); if (!swr_ctx) { printf("swr_alloc error \n"); __android_log_print(ANDROID_LOG_DEBUG, TAG, "stream13"); return -1; } src_ch_layout = (audio_dec_ctx->channel_layout && audio_dec_ctx->channels == av_get_channel_layout_nb_channels(audio_dec_ctx->channel_layout)) ? audio_dec_ctx->channel_layout : av_get_default_channel_layout(audio_dec_ctx->channels); if (out_channels == 1) { dst_ch_layout = AV_CH_LAYOUT_MONO; } else if (out_channels == 2) { dst_ch_layout = AV_CH_LAYOUT_STEREO; } else { //可扩展 } __android_log_print(ANDROID_LOG_DEBUG, TAG, "stream12-2"); if (src_ch_layout <= 0) { printf("src_ch_layout error \n"); __android_log_print(ANDROID_LOG_DEBUG, TAG, "stream14"); return -1; } __android_log_print(ANDROID_LOG_DEBUG, TAG, "stream12-3"); src_nb_samples = pAudioDecodeFrame->nb_samples; if (src_nb_samples <= 0) { printf("src_nb_samples error \n"); __android_log_print(ANDROID_LOG_DEBUG, TAG, "stream15"); return -1; } /* set options */ av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(swr_ctx, "in_sample_rate", audio_dec_ctx->sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", audio_dec_ctx->sample_fmt, 0); av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(swr_ctx, "out_sample_rate", out_sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", (AVSampleFormat) out_sample_fmt, 0); swr_init(swr_ctx); max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, out_sample_rate, audio_dec_ctx->sample_rate, AV_ROUND_UP); if (max_dst_nb_samples <= 0) { printf("av_rescale_rnd error \n"); return -1; } dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout); ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, (AVSampleFormat) out_sample_fmt, 0); if (ret < 0) { printf("av_samples_alloc_array_and_samples error \n"); return -1; } dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, audio_dec_ctx->sample_rate) + src_nb_samples, out_sample_rate, audio_dec_ctx->sample_rate, AV_ROUND_UP); if (dst_nb_samples <= 0) { return -1; } if (dst_nb_samples > max_dst_nb_samples) { av_free(dst_data[0]); ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, (AVSampleFormat) out_sample_fmt, 1); max_dst_nb_samples = dst_nb_samples; } data_size = av_samples_get_buffer_size(NULL, audio_dec_ctx->channels, pAudioDecodeFrame->nb_samples, audio_dec_ctx->sample_fmt, 1); if (data_size <= 0) { return -1; } resampled_data_size = data_size; if (swr_ctx) { ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **) pAudioDecodeFrame->data, pAudioDecodeFrame->nb_samples); if (ret <= 0) { return -1; } resampled_data_size = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, ret, (AVSampleFormat) out_sample_fmt, 1); if (resampled_data_size <= 0) { return -1; } } else { return -1; } //将值返回去 memcpy(out_buf, dst_data[0], resampled_data_size); if (dst_data) { av_freep(&dst_data[0]); } av_freep(&dst_data); dst_data = NULL; if (swr_ctx) { swr_free(&swr_ctx); } return resampled_data_size; }
int decode_frame_from_packet(VideoState *is, AVFrame decoded_frame) { int64_t src_ch_layout, dst_ch_layout; int src_rate, dst_rate; uint8_t **src_data = NULL, **dst_data = NULL; int src_nb_channels = 0, dst_nb_channels = 0; int src_linesize, dst_linesize; int src_nb_samples, dst_nb_samples, max_dst_nb_samples; enum AVSampleFormat src_sample_fmt, dst_sample_fmt; int dst_bufsize; int ret; src_nb_samples = decoded_frame.nb_samples; src_linesize = (int) decoded_frame.linesize; src_data = decoded_frame.data; if (decoded_frame.channel_layout == 0) { decoded_frame.channel_layout = av_get_default_channel_layout(decoded_frame.channels); } src_rate = decoded_frame.sample_rate; dst_rate = decoded_frame.sample_rate; src_ch_layout = decoded_frame.channel_layout; dst_ch_layout = decoded_frame.channel_layout; src_sample_fmt = decoded_frame.format; dst_sample_fmt = AV_SAMPLE_FMT_S16; av_opt_set_int(is->sws_ctx_audio, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(is->sws_ctx_audio, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(is->sws_ctx_audio, "in_sample_rate", src_rate, 0); av_opt_set_int(is->sws_ctx_audio, "out_sample_rate", dst_rate, 0); av_opt_set_sample_fmt(is->sws_ctx_audio, "in_sample_fmt", src_sample_fmt, 0); av_opt_set_sample_fmt(is->sws_ctx_audio, "out_sample_fmt", dst_sample_fmt, 0); /* initialize the resampling context */ if ((ret = swr_init(is->sws_ctx_audio)) < 0) { fprintf(stderr, "Failed to initialize the resampling context\n"); return -1; } /* allocate source and destination samples buffers */ src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout); ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels, src_nb_samples, src_sample_fmt, 0); if (ret < 0) { fprintf(stderr, "Could not allocate source samples\n"); return -1; } /* compute the number of converted samples: buffering is avoided * ensuring that the output buffer will contain at least all the * converted input samples */ max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); /* buffer is going to be directly written to a rawaudio file, no alignment */ dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout); ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, dst_sample_fmt, 0); if (ret < 0) { fprintf(stderr, "Could not allocate destination samples\n"); return -1; } /* compute destination number of samples */ dst_nb_samples = av_rescale_rnd(swr_get_delay(is->sws_ctx_audio, src_rate) + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); /* convert to destination format */ ret = swr_convert(is->sws_ctx_audio, dst_data, dst_nb_samples, (const uint8_t **)decoded_frame.data, src_nb_samples); if (ret < 0) { fprintf(stderr, "Error while converting\n"); return -1; } dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, ret, dst_sample_fmt, 1); if (dst_bufsize < 0) { fprintf(stderr, "Could not get sample buffer size\n"); return -1; } memcpy(is->audio_buf, dst_data[0], dst_bufsize); if (src_data) { av_freep(&src_data[0]); } av_freep(&src_data); if (dst_data) { av_freep(&dst_data[0]); } av_freep(&dst_data); return dst_bufsize; }
static double get_delay(struct af_resample *s) { int64_t base = s->in_rate * (int64_t)s->out_rate; return swr_get_delay(s->avrctx, base) / (double)base; }
QbPacket ConvertAudio::convert(const QbAudioPacket &packet, const QbCaps &oCaps) { QbAudioCaps oAudioCaps(oCaps); int64_t iSampleLayout = channelLayouts->value(packet.caps().layout(), 0); AVSampleFormat iSampleFormat = sampleFormats->value(packet.caps().format(), AV_SAMPLE_FMT_NONE); int iSampleRate = packet.caps().rate(); int iNChannels = packet.caps().channels(); int iNSamples = packet.caps().samples(); int64_t oSampleLayout = channelLayouts->value(oAudioCaps.layout(), AV_CH_LAYOUT_STEREO); AVSampleFormat oSampleFormat = sampleFormats->value(oAudioCaps.format(), AV_SAMPLE_FMT_FLT); int oSampleRate = oAudioCaps.rate(); int oNChannels = oAudioCaps.channels(); this->m_resampleContext = swr_alloc_set_opts(this->m_resampleContext, oSampleLayout, oSampleFormat, oSampleRate, iSampleLayout, iSampleFormat, iSampleRate, 0, NULL); if (!this->m_resampleContext) return QbPacket(); if (!swr_is_initialized(this->m_resampleContext)) if (swr_init(this->m_resampleContext) < 0) return QbPacket(); // Create input audio frame. static AVFrame iFrame; memset(&iFrame, 0, sizeof(AVFrame)); if (av_samples_fill_arrays(iFrame.data, iFrame.linesize, (const uint8_t *) packet.buffer().data(), iNChannels, iNSamples, iSampleFormat, 1) < 0) return QbPacket(); iFrame.channels = iNChannels; iFrame.channel_layout = iSampleLayout; iFrame.format = iSampleFormat; iFrame.sample_rate = iSampleRate; iFrame.nb_samples = iNSamples; iFrame.pts = iFrame.pkt_pts = packet.pts(); // Create output audio packet. int oNSamples = swr_get_delay(this->m_resampleContext, oSampleRate) + iFrame.nb_samples * (int64_t) oSampleRate / iSampleRate + 3; int oLineSize; int oBufferSize = av_samples_get_buffer_size(&oLineSize, oNChannels, oNSamples, oSampleFormat, 1); QByteArray oBuffer(oBufferSize, Qt::Uninitialized); int oNPlanes = av_sample_fmt_is_planar(oSampleFormat)? oNChannels: 1; QVector<uint8_t *> oData(oNPlanes); if (av_samples_fill_arrays(&oData.data()[0], &oLineSize, (const uint8_t *) oBuffer.data(), oNChannels, oNSamples, oSampleFormat, 1) < 0) return QbPacket(); int64_t oPts = swr_next_pts(this->m_resampleContext, iFrame.pts); // convert to destination format int outputSamples = swr_convert(this->m_resampleContext, oData.data(), oNSamples, (const uint8_t **) iFrame.data, iFrame.nb_samples); if (outputSamples < 1) return QbPacket(); oBufferSize = oBufferSize * outputSamples / oNSamples; QbBufferPtr buffer(new char[oBufferSize]); memcpy(buffer.data(), oBuffer.data(), oBufferSize); QbAudioPacket oAudioPacket; oAudioPacket.caps() = oAudioCaps; oAudioPacket.caps().samples() = outputSamples; oAudioPacket.buffer() = buffer; oAudioPacket.bufferSize() = oBufferSize; oAudioPacket.pts() = oPts; oAudioPacket.timeBase() = QbFrac(1, oAudioCaps.rate()); oAudioPacket.index() = packet.index(); oAudioPacket.id() = packet.id(); return oAudioPacket.toPacket(); }