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; }
static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AudioEchoContext *s = ctx->priv; float volume = 1.0; int i; for (i = 0; i < s->nb_echoes; i++) { s->samples[i] = s->delay[i] * outlink->sample_rate / 1000.0; s->max_samples = FFMAX(s->max_samples, s->samples[i]); volume += s->decay[i]; } if (s->max_samples <= 0) { av_log(ctx, AV_LOG_ERROR, "Nothing to echo - missing delay samples.\n"); return AVERROR(EINVAL); } s->fade_out = s->max_samples; if (volume * s->in_gain * s->out_gain > 1.0) av_log(ctx, AV_LOG_WARNING, "out_gain %f can cause saturation of output\n", s->out_gain); switch (outlink->format) { case AV_SAMPLE_FMT_DBLP: s->echo_samples = echo_samples_dblp; break; case AV_SAMPLE_FMT_FLTP: s->echo_samples = echo_samples_fltp; break; case AV_SAMPLE_FMT_S16P: s->echo_samples = echo_samples_s16p; break; case AV_SAMPLE_FMT_S32P: s->echo_samples = echo_samples_s32p; break; } if (s->delayptrs) av_freep(&s->delayptrs[0]); av_freep(&s->delayptrs); return av_samples_alloc_array_and_samples(&s->delayptrs, NULL, outlink->channels, s->max_samples, outlink->format, 0); }
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; }
static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; FlangerContext *s = ctx->priv; s->max_samples = (s->delay_min + s->delay_depth) * inlink->sample_rate + 2.5; s->lfo_length = inlink->sample_rate / s->speed; s->delay_last = av_calloc(inlink->channels, sizeof(*s->delay_last)); s->lfo = av_calloc(s->lfo_length, sizeof(*s->lfo)); if (!s->lfo || !s->delay_last) return AVERROR(ENOMEM); ff_generate_wave_table(s->wave_shape, AV_SAMPLE_FMT_FLT, s->lfo, s->lfo_length, floor(s->delay_min * inlink->sample_rate + 0.5), s->max_samples - 2., 3 * M_PI_2); return av_samples_alloc_array_and_samples(&s->delay_buffer, NULL, inlink->channels, s->max_samples, inlink->format, 0); }
int AudioEncode::open(AVCodecID codec_id, int flags) { mCodec = avcodec_find_encoder(codec_id); if (!mCodec) { fprintf(stderr, "Couldn't find encoder: %s\n", avcodec_get_name(codec_id)); return -1; } mCodecCtx = avcodec_alloc_context3(mCodec); if (!mCodecCtx) { fprintf(stderr, "allocate codec context failed.\n"); return -1; } mFlags |= flags; mChannelNum = av_get_channel_layout_nb_channels(mChannelLayout); mMaxSamplesCount = mCodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ? 10000 : mCodecCtx->frame_size; mFifo = av_audio_fifo_alloc(mSampleFmt, mChannelNum, mMaxSamplesCount); av_samples_alloc_array_and_samples(&mData, NULL, mChannelNum, mMaxSamplesCount, mSampleFmt, 0); return 0; }
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; }
bool FFMpegLoader::open(qint64 &position) { if (!AbstractFFMpegLoader::open(position)) { return false; } int res = 0; char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; auto codecParams = fmtContext->streams[streamId]->codecpar; codecContext = avcodec_alloc_context3(nullptr); if (!codecContext) { LOG(("Audio Error: Unable to avcodec_alloc_context3 for file '%1', data size '%2'").arg(_file.name()).arg(_data.size())); return false; } if ((res = avcodec_parameters_to_context(codecContext, codecParams)) < 0) { LOG(("Audio Error: Unable to avcodec_parameters_to_context 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 false; } av_codec_set_pkt_timebase(codecContext, fmtContext->streams[streamId]->time_base); av_opt_set_int(codecContext, "refcounted_frames", 1, 0); if ((res = avcodec_open2(codecContext, codec, 0)) < 0) { LOG(("Audio Error: Unable to avcodec_open2 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 false; } auto layout = codecParams->channel_layout; if (!layout) { auto channelsCount = codecParams->channels; switch (channelsCount) { case 1: layout = AV_CH_LAYOUT_MONO; break; case 2: layout = AV_CH_LAYOUT_STEREO; break; default: LOG(("Audio Error: Unknown channel layout for %1 channels.").arg(channelsCount)); break; } } inputFormat = codecContext->sample_fmt; switch (layout) { case AV_CH_LAYOUT_MONO: switch (inputFormat) { case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: fmt = AL_FORMAT_MONO8; sampleSize = 1; break; case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S16P: fmt = AL_FORMAT_MONO16; sampleSize = sizeof(uint16); break; default: sampleSize = -1; // convert needed break; } break; case AV_CH_LAYOUT_STEREO: switch (inputFormat) { case AV_SAMPLE_FMT_U8: fmt = AL_FORMAT_STEREO8; sampleSize = 2; break; case AV_SAMPLE_FMT_S16: fmt = AL_FORMAT_STEREO16; sampleSize = 2 * sizeof(uint16); break; default: sampleSize = -1; // convert needed break; } break; default: sampleSize = -1; // convert needed break; } if (_samplesFrequency != 44100 && _samplesFrequency != 48000) { sampleSize = -1; // convert needed } if (sampleSize < 0) { swrContext = swr_alloc(); if (!swrContext) { LOG(("Audio Error: Unable to swr_alloc for file '%1', data size '%2'").arg(_file.name()).arg(_data.size())); return false; } int64_t src_ch_layout = layout, dst_ch_layout = AudioToChannelLayout; srcRate = _samplesFrequency; AVSampleFormat src_sample_fmt = inputFormat, dst_sample_fmt = AudioToFormat; dstRate = (_samplesFrequency != 44100 && _samplesFrequency != 48000) ? Media::Player::kDefaultFrequency : _samplesFrequency; av_opt_set_int(swrContext, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(swrContext, "in_sample_rate", srcRate, 0); av_opt_set_sample_fmt(swrContext, "in_sample_fmt", src_sample_fmt, 0); av_opt_set_int(swrContext, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(swrContext, "out_sample_rate", dstRate, 0); av_opt_set_sample_fmt(swrContext, "out_sample_fmt", dst_sample_fmt, 0); if ((res = swr_init(swrContext)) < 0) { LOG(("Audio Error: Unable to swr_init 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 false; } sampleSize = AudioToChannels * sizeof(short); _samplesFrequency = dstRate; _samplesCount = av_rescale_rnd(_samplesCount, dstRate, srcRate, AV_ROUND_UP); position = av_rescale_rnd(position, dstRate, srcRate, AV_ROUND_DOWN); fmt = AL_FORMAT_STEREO16; maxResampleSamples = av_rescale_rnd(AVBlockSize / sampleSize, dstRate, srcRate, AV_ROUND_UP); if ((res = av_samples_alloc_array_and_samples(&dstSamplesData, 0, AudioToChannels, maxResampleSamples, AudioToFormat, 0)) < 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 false; } } if (position) { int64 ts = (position * fmtContext->streams[streamId]->time_base.den) / (_samplesFrequency * fmtContext->streams[streamId]->time_base.num); if (av_seek_frame(fmtContext, streamId, ts, AVSEEK_FLAG_ANY) < 0) { if (av_seek_frame(fmtContext, streamId, ts, 0) < 0) { } } } return true; }
static void open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st) { AVCodecContext *c; int ret; c = st->codec; /* allocate and init a re-usable frame */ audio_frame = av_frame_alloc(); if (!audio_frame) { fprintf(stderr, "Could not allocate audio frame\n"); exit(1); } /* open it */ ret = avcodec_open2(c, codec, NULL); if (ret < 0) { fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret)); exit(1); } /* init signal generator */ t = 0; tincr = 2 * M_PI * 110.0 / c->sample_rate; /* increment frequency by 110 Hz per second */ tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate; src_nb_samples = c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ? 10000 : c->frame_size; ret = av_samples_alloc_array_and_samples(&src_samples_data, &src_samples_linesize, c->channels, src_nb_samples, AV_SAMPLE_FMT_S16, 0); if (ret < 0) { fprintf(stderr, "Could not allocate source samples\n"); exit(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 = src_nb_samples; /* create resampler context */ if (c->sample_fmt != AV_SAMPLE_FMT_S16) { swr_ctx = swr_alloc(); if (!swr_ctx) { fprintf(stderr, "Could not allocate resampler context\n"); exit(1); } /* set options */ av_opt_set_int (swr_ctx, "in_channel_count", c->channels, 0); av_opt_set_int (swr_ctx, "in_sample_rate", c->sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int (swr_ctx, "out_channel_count", c->channels, 0); av_opt_set_int (swr_ctx, "out_sample_rate", c->sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", c->sample_fmt, 0); /* initialize the resampling context */ if ((ret = swr_init(swr_ctx)) < 0) { fprintf(stderr, "Failed to initialize the resampling context\n"); exit(1); } ret = av_samples_alloc_array_and_samples(&dst_samples_data, &dst_samples_linesize, c->channels, max_dst_nb_samples, c->sample_fmt, 0); if (ret < 0) { fprintf(stderr, "Could not allocate destination samples\n"); exit(1); } } else { dst_samples_data = src_samples_data; } dst_samples_size = av_samples_get_buffer_size(NULL, c->channels, max_dst_nb_samples, c->sample_fmt, 0); }
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; }
const CGEAudioFrameBufferData* CGEVideoDecodeHandler::getCurrentAudioFrame() { if(m_context->pSwrCtx == nullptr) { if(m_context->pAudioStream->codec->sample_fmt != AV_SAMPLE_FMT_S16) { m_context->pSwrCtx = swr_alloc(); if(m_context->pSwrCtx == nullptr) { CGE_LOG_ERROR("Allocate resampler context failed!\n"); return nullptr; } auto ctx = m_context->pSwrCtx; auto c = m_context->pAudioStream->codec; av_opt_set_int (ctx, "in_channel_count", c->channels, 0); av_opt_set_int (ctx, "in_sample_rate", c->sample_rate, 0); av_opt_set_sample_fmt(ctx, "in_sample_fmt", c->sample_fmt, 0); av_opt_set_int (ctx, "out_channel_count", 1, 0); av_opt_set_int (ctx, "out_sample_rate", c->sample_rate, 0); av_opt_set_sample_fmt(ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); int ret; if ((ret = swr_init(ctx)) < 0) { CGE_LOG_ERROR("Failed to initialize the resampling context: %d\n", ret); return nullptr; } m_context->maxDstNbSamples = c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ? 10000 : c->frame_size; ret = av_samples_alloc_array_and_samples(&m_context->dstSampleData, &m_context->dstSamplesLinesize, c->channels, m_context->maxDstNbSamples, c->sample_fmt, 0); if (ret < 0) { CGE_LOG_ERROR("Could not allocate destination samples\n"); return nullptr; } m_context->dstSamplesSize = av_samples_get_buffer_size(NULL, c->channels, m_context->maxDstNbSamples, c->sample_fmt, 0); } else { CGE_LOG_ERROR("errorxxxx"); } } int ret = swr_convert(m_context->pSwrCtx, m_context->dstSampleData, m_context->dstSamplesSize, (const uint8_t**)m_context->pAudioFrame->data, m_context->pAudioFrame->nb_samples); if(ret <= 0) return nullptr; m_cachedAudioFrame.timestamp = av_frame_get_best_effort_timestamp(m_context->pAudioFrame); m_cachedAudioFrame.data = m_context->dstSampleData[0]; m_cachedAudioFrame.nbSamples = m_context->pAudioFrame->nb_samples; m_cachedAudioFrame.channels = 1;//av_frame_get_channels(m_context->pAudioFrame); m_cachedAudioFrame.bytesPerSample = 2; m_cachedAudioFrame.linesize = m_context->dstSamplesSize; m_cachedAudioFrame.format = CGE_SAMPLE_FMT_S16; return &m_cachedAudioFrame; }
bool ChildFFMpegLoader::open(qint64 &position) { int res = 0; char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; uint64_t layout = _parentData->context->channel_layout; _inputFormat = _parentData->context->sample_fmt; switch (layout) { case AV_CH_LAYOUT_MONO: switch (_inputFormat) { case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: _format = AL_FORMAT_MONO8; _sampleSize = 1; break; case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S16P: _format = AL_FORMAT_MONO16; _sampleSize = sizeof(uint16); break; default: _sampleSize = -1; // convert needed break; } break; case AV_CH_LAYOUT_STEREO: switch (_inputFormat) { case AV_SAMPLE_FMT_U8: _format = AL_FORMAT_STEREO8; _sampleSize = 2; break; case AV_SAMPLE_FMT_S16: _format = AL_FORMAT_STEREO16; _sampleSize = 2 * sizeof(uint16); break; default: _sampleSize = -1; // convert needed break; } break; default: _sampleSize = -1; // convert needed break; } if (_parentData->frequency != 44100 && _parentData->frequency != 48000) { _sampleSize = -1; // convert needed } if (_sampleSize < 0) { _swrContext = swr_alloc(); if (!_swrContext) { LOG(("Audio Error: Unable to swr_alloc for file '%1', data size '%2'").arg(file.name()).arg(data.size())); return false; } int64_t src_ch_layout = layout, dst_ch_layout = AudioToChannelLayout; _srcRate = _parentData->frequency; AVSampleFormat src_sample_fmt = _inputFormat, dst_sample_fmt = AudioToFormat; _dstRate = (_parentData->frequency != 44100 && _parentData->frequency != 48000) ? AudioVoiceMsgFrequency : _parentData->frequency; av_opt_set_int(_swrContext, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(_swrContext, "in_sample_rate", _srcRate, 0); av_opt_set_sample_fmt(_swrContext, "in_sample_fmt", src_sample_fmt, 0); av_opt_set_int(_swrContext, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(_swrContext, "out_sample_rate", _dstRate, 0); av_opt_set_sample_fmt(_swrContext, "out_sample_fmt", dst_sample_fmt, 0); if ((res = swr_init(_swrContext)) < 0) { LOG(("Audio Error: Unable to swr_init 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 false; } _sampleSize = AudioToChannels * sizeof(short); _parentData->frequency = _dstRate; _parentData->length = av_rescale_rnd(_parentData->length, _dstRate, _srcRate, AV_ROUND_UP); position = av_rescale_rnd(position, _dstRate, _srcRate, AV_ROUND_DOWN); _format = AL_FORMAT_STEREO16; _maxResampleSamples = av_rescale_rnd(AVBlockSize / _sampleSize, _dstRate, _srcRate, AV_ROUND_UP); if ((res = av_samples_alloc_array_and_samples(&_dstSamplesData, 0, AudioToChannels, _maxResampleSamples, AudioToFormat, 0)) < 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 false; } } return true; }
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 videoDecodingThread(ThreadInfo* p_threadInfo) { // Read ThreadInfo struct, then delete it FFmpegVideoPlayer* videoPlayer = p_threadInfo->videoPlayer; VideoInfo& videoInfo = videoPlayer->getVideoInfo(); boost::mutex* playerMutex = p_threadInfo->playerMutex; boost::condition_variable* playerCondVar = p_threadInfo->playerCondVar; boost::mutex* decodeMutex = p_threadInfo->decodingMutex; boost::condition_variable* decodeCondVar = p_threadInfo->decodingCondVar; bool isLoop = p_threadInfo->isLoop; staticOgreLog = videoPlayer->getLog(); delete p_threadInfo; // Initialize FFmpeg av_register_all(); av_log_set_callback(log_callback); av_log_set_level(AV_LOG_WARNING); // Initialize video decoding, filling the VideoInfo // Open the input file AVFormatContext* formatContext = NULL; const char* name = videoPlayer->getVideoFilename().c_str(); if (avformat_open_input(&formatContext, name, NULL, NULL) < 0) { videoInfo.error = "Could not open input: "; videoInfo.error.append(videoPlayer->getVideoFilename()); playerCondVar->notify_all(); return; } // Read stream information if (avformat_find_stream_info(formatContext, NULL) < 0) { videoInfo.error = "Could not find stream information."; playerCondVar->notify_all(); return; } // Get streams // Audio stream AVStream* audioStream = NULL; AVCodecContext* audioCodecContext = NULL; int audioStreamIndex = -1; if (!openCodecContext(formatContext, AVMEDIA_TYPE_AUDIO, videoInfo, audioStreamIndex)) { // The error itself is set by openCodecContext playerCondVar->notify_all(); return; } audioStream = formatContext->streams[audioStreamIndex]; audioCodecContext = audioStream->codec; // Video stream AVStream* videoStream = NULL; AVCodecContext* videoCodecContext = NULL; int videoStreamIndex = -1; if (!openCodecContext(formatContext, AVMEDIA_TYPE_VIDEO, videoInfo, videoStreamIndex)) { // The error itself is set by openCodecContext playerCondVar->notify_all(); return; } videoStream = formatContext->streams[videoStreamIndex]; videoCodecContext = videoStream->codec; // Dump information av_dump_format(formatContext, 0, videoPlayer->getVideoFilename().c_str(), 0); // Store useful information in VideoInfo struct double timeBase = ((double)audioStream->time_base.num) / (double)audioStream->time_base.den; videoInfo.audioDuration = audioStream->duration * timeBase; videoInfo.audioSampleRate = audioCodecContext->sample_rate; videoInfo.audioBitRate = audioCodecContext->bit_rate; videoInfo.audioNumChannels = videoInfo.audioNumChannels > 0 ? videoInfo.audioNumChannels : audioCodecContext->channels; timeBase = ((double)videoStream->time_base.num) / (double)videoStream->time_base.den; videoInfo.videoDuration = videoStream->duration * timeBase; videoInfo.videoWidth = videoCodecContext->width; videoInfo.videoHeight = videoCodecContext->height; // If the a duration is below 0 seconds, something is very fishy. // Use format duration instead, it's the best guess we have if (videoInfo.audioDuration < 0.0) { videoInfo.audioDuration = ((double)formatContext->duration) / AV_TIME_BASE; } if (videoInfo.videoDuration < 0.0) { videoInfo.videoDuration = ((double)formatContext->duration) / AV_TIME_BASE; } // Store the longer of both durations. This is what determines when looped videos // will begin anew videoInfo.longerDuration = videoInfo.videoDuration > videoInfo.audioDuration ? videoInfo.videoDuration : videoInfo.audioDuration; // Wake up video player videoInfo.infoFilled = true; playerCondVar->notify_all(); // Initialize packet, set data to NULL, let the demuxer fill it AVPacket packet; av_init_packet(&packet); packet.data = NULL; packet.size = 0; // Initialize SWS context SwsContext* swsContext = NULL; swsContext = sws_getCachedContext(swsContext, videoInfo.videoWidth, videoInfo.videoHeight, videoCodecContext->pix_fmt, videoInfo.videoWidth, videoInfo.videoHeight, PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); // Create destination picture AVFrame* destPic = avcodec_alloc_frame(); avpicture_alloc((AVPicture*)destPic, PIX_FMT_RGBA, videoInfo.videoWidth, videoInfo.videoHeight); // Get the correct target channel layout uint64_t targetChannelLayout; // Keep the source layout if (audioCodecContext->channels == videoInfo.audioNumChannels) { targetChannelLayout = audioCodecContext->channel_layout; } // Or determine a new one else { switch (videoInfo.audioNumChannels) { case 1: targetChannelLayout = AV_CH_LAYOUT_MONO; break; case 2: targetChannelLayout = AV_CH_LAYOUT_STEREO; break; default: targetChannelLayout = audioCodecContext->channel_layout; break; } } // Initialize SWR context SwrContext* swrContext = swr_alloc_set_opts(NULL, targetChannelLayout, AV_SAMPLE_FMT_FLT, audioCodecContext->sample_rate, audioCodecContext->channel_layout, audioCodecContext->sample_fmt, audioCodecContext->sample_rate, 0, NULL); int result = swr_init(swrContext); if (result != 0) { videoInfo.error = "Could not initialize swr context: " + boost::lexical_cast<std::string>(result); playerCondVar->notify_all(); return; } // Create destination sample buffer uint8_t** destBuffer = NULL; int destBufferLinesize; av_samples_alloc_array_and_samples( &destBuffer, &destBufferLinesize, videoInfo.audioNumChannels, 2048, AV_SAMPLE_FMT_FLT, 0); // Main decoding loop // Read the input file frame by frame AVFrame* frame = NULL; while (av_read_frame(formatContext, &packet) >= 0) { // Only start decoding when at least one of the buffers is not full while (videoPlayer->getVideoBufferIsFull() && videoPlayer->getAudioBufferIsFull()) { boost::unique_lock<boost::mutex> lock(*decodeMutex); boost::chrono::steady_clock::time_point const timeOut = boost::chrono::steady_clock::now() + boost::chrono::milliseconds((int)videoPlayer->getBufferTarget() * 1000); decodeCondVar->wait_until(lock, timeOut); if (videoInfo.decodingAborted) { break; } } // Break if the decoding was aborted if (videoInfo.decodingAborted) { break; } // Initialize frame if (!frame) { if (!(frame = avcodec_alloc_frame())) { videoInfo.error = "Out of memory."; return; } } else { avcodec_get_frame_defaults(frame); } // Decode the packet AVPacket orig_pkt = packet; do { int decoded = 0; if (packet.stream_index == audioStreamIndex) { decoded = decodeAudioPacket(packet, audioCodecContext, audioStream, frame, swrContext, destBuffer, destBufferLinesize, videoPlayer, videoInfo, isLoop); } else if (packet.stream_index == videoStreamIndex) { decoded = decodeVideoPacket(packet, videoCodecContext, videoStream, frame, swsContext, (AVPicture*)destPic, videoPlayer, videoInfo, isLoop); } else { // This means that we have a stream that is neither our video nor audio stream // Just skip the package break; } // decoded will be negative on an error if (decoded < 0) { // The error itself is set by the decode functions playerCondVar->notify_all(); return; } // Increment data pointer, subtract from size packet.data += decoded; packet.size -= decoded; } while (packet.size > 0); av_free_packet(&orig_pkt); } // We're done. Close everything avcodec_free_frame(&frame); avpicture_free((AVPicture*)destPic); avcodec_free_frame(&destPic); avcodec_close(videoCodecContext); avcodec_close(audioCodecContext); sws_freeContext(swsContext); av_freep(&destBuffer[0]); swr_free(&swrContext); avformat_close_input(&formatContext); videoInfo.audioDuration = videoInfo.audioDecodedDuration; videoInfo.decodingDone = videoInfo.decodingAborted ? false : true; }
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 = 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"); 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) { 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); if (dst_bufsize < 0) { fprintf(stderr, "Could not get sample buffer size\n"); goto end; } 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; }
bool MpegLoader::open() { if (!BaseMpegLoader::open()) return false; int res = 0; av_opt_set_int(FmtContext_->streams[StreamId_]->codec, "refcounted_frames", 1, 0); if ((res = avcodec_open2(FmtContext_->streams[StreamId_]->codec, Codec_, 0)) < 0) return false; CodecContext_ = FmtContext_->streams[StreamId_]->codec; uint64_t layout = CodecContext_->channel_layout; InputFormat_ = CodecContext_->sample_fmt; switch (layout) { case AV_CH_LAYOUT_MONO: switch (InputFormat_) { case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: Fmt_ = AL_FORMAT_MONO8; SampleSize_ = 1; break; case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S16P: Fmt_ = AL_FORMAT_MONO16; SampleSize_ = sizeof(quint16); break; default: SampleSize_ = -1; break; } break; case AV_CH_LAYOUT_STEREO: switch (InputFormat_) { case AV_SAMPLE_FMT_U8: Fmt_ = AL_FORMAT_STEREO8; SampleSize_ = 2; break; case AV_SAMPLE_FMT_S16: Fmt_ = AL_FORMAT_STEREO16; SampleSize_ = 2 * sizeof(quint16); break; default: SampleSize_ = -1; break; } break; default: SampleSize_ = -1; break; } if (Freq_ != 44100 && Freq_ != 48000) SampleSize_ = -1; if (SampleSize_ < 0) { SwrContext_ = swr_alloc(); if (!SwrContext_) return false; int64_t src_ch_layout = layout, dst_ch_layout = OutChannelLayout; SrcRate_ = Freq_; AVSampleFormat src_sample_fmt = InputFormat_, dst_sample_fmt = OutFormat; DstRate_ = (Freq_ != 44100 && Freq_ != 48000) ? OutFrequency : Freq_; av_opt_set_int(SwrContext_, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(SwrContext_, "in_sample_rate", SrcRate_, 0); av_opt_set_sample_fmt(SwrContext_, "in_sample_fmt", src_sample_fmt, 0); av_opt_set_int(SwrContext_, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(SwrContext_, "out_sample_rate", DstRate_, 0); av_opt_set_sample_fmt(SwrContext_, "out_sample_fmt", dst_sample_fmt, 0); if ((res = swr_init(SwrContext_)) < 0) return false; SampleSize_ = OutChannels * sizeof(short); Freq_ = DstRate_; Len_ = av_rescale_rnd(Len_, DstRate_, SrcRate_, AV_ROUND_UP); Fmt_ = AL_FORMAT_STEREO16; MaxResampleSamples_ = av_rescale_rnd(BlockSize / SampleSize_, DstRate_, SrcRate_, AV_ROUND_UP); if ((res = av_samples_alloc_array_and_samples(&OutSamplesData_, 0, OutChannels, MaxResampleSamples_, OutFormat, 0)) < 0) return false; } return true; }
//音频线程 void *audio_thread(void *minstance){ playInstance *instance = (playInstance *)minstance; LOGE("音频线程开启\n"); JNIEnv *audioEnv; (*(instance->gJavaVm))->AttachCurrentThread(instance->gJavaVm,&audioEnv,NULL); jclass javacls = (*audioEnv)->GetObjectClass(audioEnv,instance->gJavaobj); jmethodID play = (*audioEnv)->GetMethodID(audioEnv,javacls,"playSound","([BI)V"); struct timespec time; time.tv_sec=10;//网络不好最多等10秒 time.tv_nsec=0; struct threadmsg msg; int packet_count = 0; while(1){ if(instance->stop){ break; } msg.data=NULL; AVPacket pavpacket; thread_queue_get(instance->audio_queue,&time,&msg); if(msg.msgtype==-1){//正常退出 break; } if(msg.data ==NULL){ LOGE("音频线程空循环\n"); continue; } packet_count++; if(packet_count == 1){//拿到第一个音频包 instance->vs->audio_start_time = av_gettime(); LOGE("音频开始时间 %lld\n",instance->vs->audio_start_time); } AVPacket *packet_p = msg.data; pavpacket = *packet_p; uint8_t ** dst_data; //延时同步 int64_t pkt_pts = pavpacket.pts; double show_time = pkt_pts * (instance->vs->audio_time_base); int64_t show_time_micro = show_time * 1000000; int64_t played_time = av_gettime() - instance->vs->audio_start_time; int64_t delta_time = show_time_micro - played_time; if(delta_time< -(0.2 * 1000000)){ av_free_packet(packet_p); av_free(msg.data); LOGE("声音跳帧\n"); continue; }else if(delta_time>0){ av_usleep(delta_time); } int len =0; int dst_linesize; while(pavpacket.size>0){ int got_frame=0; len = avcodec_decode_audio4(instance->vs->aCodecCtx,instance->vs->audio_decode_frame,&got_frame,&pavpacket); if(len<0){ LOGE("audio decode return wrong"); break; } //音频转化 av_samples_alloc_array_and_samples(&dst_data,&dst_linesize,1,(instance->vs->audio_decode_frame)->nb_samples,AV_SAMPLE_FMT_S16,0); swr_convert(instance->vs->swr_ctx,dst_data,(instance->vs->audio_decode_frame)->nb_samples,(const uint8_t **)&(instance->vs->audio_decode_frame->data[0]),(instance->vs->audio_decode_frame)->nb_samples); pavpacket.size -= len; pavpacket.data += len; if(got_frame){ jbyte *bytes = (*audioEnv)->GetByteArrayElements(audioEnv, instance->global_aarray, NULL); memcpy(bytes,*dst_data,dst_linesize); (*audioEnv)->ReleaseByteArrayElements(audioEnv, instance->global_aarray, bytes, 0); (*audioEnv)->CallVoidMethod(audioEnv,instance->gJavaobj,play,instance->global_aarray,dst_linesize); } av_free(dst_data[0]); } av_free_packet(packet_p); av_free(msg.data); } (*(instance->gJavaVm))->DetachCurrentThread(instance->gJavaVm); LOGE("音频线程退出\n"); return NULL; }
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; }
int initializeMuxer(const char *formatName, const char *fileName, PCAST_CONFIGURATION config) { AVOutputFormat *format; AVCodec *audCodec; int ret; av_register_all(); avformat_network_init(); hasWrittenStreamHeader = 0; spsLength = 0; ppsLength = 0; pthread_mutex_init(&streamLock, NULL); format = av_guess_format(formatName, fileName, NULL); if (format == NULL) { fprintf(stderr, "av_guess_format() failed\n"); return -1; } formatContext = avformat_alloc_context(); if (formatContext == NULL) { fprintf(stderr, "avformat_alloc_context() failed\n"); return -2; } // Initialize the AVFormatContext formatContext->oformat = format; strcpy(formatContext->filename, fileName); if (config->muxEnableFlags & ENABLE_VIDEO) { // Add the video stream videoStream = avformat_new_stream(formatContext, NULL); if (videoStream == NULL) { fprintf(stderr, "avformat_new_stream() #1 failed\n"); return -3; } // Configure the video codec videoCodecCtx = videoStream->codec; videoCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; videoCodecCtx->codec_id = AV_CODEC_ID_H264; videoCodecCtx->bit_rate = 0; videoCodecCtx->width = config->width; videoCodecCtx->height = config->height; videoCodecCtx->time_base.den = config->frameRate; videoCodecCtx->time_base.num = 1; videoCodecCtx->gop_size = config->frameRate * config->iFrameInterval; videoCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; } if (config->muxEnableFlags & ENABLE_AUDIO) { audCodec = avcodec_find_encoder(AV_CODEC_ID_AAC); if (audCodec == NULL) { fprintf(stderr, "avcodec_find_encoder failed\n"); return -4; } // Add the audio stream audioStream = avformat_new_stream(formatContext, audCodec); if (audioStream == NULL) { fprintf(stderr, "avformat_new_stream() #2 failed\n"); return -5; } // Configure the audio codec audioCodecCtx = audioStream->codec; audioCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO; audioCodecCtx->codec_id = AV_CODEC_ID_AAC; audioCodecCtx->bit_rate = config->audioBitrate; audioCodecCtx->sample_rate = 44100; audioCodecCtx->channels = config->audioChannels; audioCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP; audioCodecCtx->profile = FF_PROFILE_AAC_LOW; audioCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; ret = avcodec_open2(audioCodecCtx, audCodec, NULL); if (ret < 0) { fprintf(stderr, "avcodec_open2() failed: %d\n", ret); return ret; } srcSamplesCount = audioCodecCtx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ? 10000 : audioCodecCtx->frame_size; ret = av_samples_alloc_array_and_samples(&srcSamplesData, &srcSamplesLinesize, audioCodecCtx->channels, srcSamplesCount, audioCodecCtx->sample_fmt, 0); if (ret < 0) { fprintf(stderr, "av_samples_alloc_array_and_samples() failed: %d\n", ret); return ret; } // Our input is 16-bit signed samples so we'll need a resampler to convert to FP swrContext = swr_alloc(); if (swrContext == NULL) { fprintf(stderr, "swr_alloc() failed\n"); return -1; } av_opt_set_int(swrContext, "in_channel_count", audioCodecCtx->channels, 0); av_opt_set_int(swrContext, "in_sample_rate", audioCodecCtx->sample_rate, 0); av_opt_set_int(swrContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int(swrContext, "out_channel_count", audioCodecCtx->channels, 0); av_opt_set_int(swrContext, "out_sample_rate", audioCodecCtx->sample_rate, 0); av_opt_set_int(swrContext, "out_sample_fmt", audioCodecCtx->sample_fmt, 0); ret = swr_init(swrContext); if (ret < 0) { fprintf(stderr, "swr_init() failed: %d\n", ret); return ret; } maxDstSamplesCount = srcSamplesCount; ret = av_samples_alloc_array_and_samples(&dstSamplesData, &dstSamplesLinesize, audioCodecCtx->channels, maxDstSamplesCount, audioCodecCtx->sample_fmt, 0); if (ret < 0) { fprintf(stderr, "av_samples_alloc_array_and_samples() failed: %d\n", ret); return ret; } dstSamplesSize = av_samples_get_buffer_size(NULL, audioCodecCtx->channels, maxDstSamplesCount, audioCodecCtx->sample_fmt, 0); } if (format->flags & AVFMT_GLOBALHEADER) { if (videoCodecCtx != NULL) { videoCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; } if (audioCodecCtx != NULL) { audioCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; } } if ((format->flags & AVFMT_NOFILE) == 0) { if ((ret = avio_open(&formatContext->pb, fileName, AVIO_FLAG_WRITE)) < 0) { fprintf(stderr, "avio_open() failed: %d\n", ret); return -4; } } return 0; }
int bl_audio_decode( char const * const filename, struct bl_song * const song) { int ret; // Contexts and libav variables AVPacket avpkt; AVFormatContext* context; int audio_stream; AVCodecContext* codec_context = NULL; AVCodec *codec = NULL; AVFrame *decoded_frame = NULL; struct SwrContext *swr_ctx; // Size of the samples uint64_t size = 0; // Dictionary to fetch tags AVDictionaryEntry *tags_dictionary; // Planar means channels are interleaved in data section // See MP3 vs FLAC for instance. int is_planar; // Pointer to beginning of music data int8_t *beginning; // Received frame holder int got_frame; // Position in the data buffer int index; // Initialize AV lib av_register_all(); context = avformat_alloc_context(); av_log_set_level(AV_LOG_QUIET); // Open input file if (avformat_open_input(&context, filename, NULL, NULL) < 0) { fprintf(stderr, "Couldn't open file: %s. Error %d encountered.\n", filename, errno); return BL_UNEXPECTED; } // Search for a valid stream if (avformat_find_stream_info(context, NULL) < 0) { fprintf(stderr, "Couldn't find stream information\n"); return BL_UNEXPECTED; } // Get audio stream audio_stream = av_find_best_stream(context, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0); if (audio_stream < 0) { fprintf(stderr, "Couldn't find a suitable audio stream\n"); return BL_UNEXPECTED; } // Find associated codec codec_context = context->streams[audio_stream]->codec; if (!codec_context) { fprintf(stderr, "Codec not found!\n"); return BL_UNEXPECTED; } if (avcodec_open2(codec_context, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); return BL_UNEXPECTED; } // Fill song properties song->filename = malloc(strlen(filename) + 1); strcpy(song->filename, filename); song->sample_rate = codec_context->sample_rate; song->duration = (uint64_t)(context->duration) / ((uint64_t)AV_TIME_BASE); song->bitrate = context->bit_rate; song->not_s16 = 0; song->nb_bytes_per_sample = av_get_bytes_per_sample(codec_context->sample_fmt); song->channels = codec_context->channels; // Get number of samples size = ( ((uint64_t)(context->duration) * (uint64_t)song->sample_rate) / ((uint64_t)AV_TIME_BASE) ) * song->channels * song->nb_bytes_per_sample; // Estimated number of samples song->nSamples = ( ( ((uint64_t)(context->duration) * (uint64_t)song->sample_rate) / ((uint64_t)AV_TIME_BASE) ) * song->channels ); // Allocate sample_array if((song->sample_array = calloc(size, 1)) == NULL) { fprintf(stderr, "Could not allocate enough memory\n"); return BL_UNEXPECTED; } beginning = song->sample_array; index = 0; // If the song is in a floating-point format or int32, prepare the conversion to int16 if(codec_context->sample_fmt != AV_SAMPLE_FMT_S16 && codec_context->sample_fmt != AV_SAMPLE_FMT_S16P) { song->not_s16 = 1; song->nb_bytes_per_sample = 2; swr_ctx = swr_alloc(); av_opt_set_int(swr_ctx, "in_channel_layout", codec_context->channel_layout, 0); av_opt_set_int(swr_ctx, "in_sample_rate", codec_context->sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", codec_context->sample_fmt, 0); av_opt_set_int(swr_ctx, "out_channel_layout", codec_context->channel_layout, 0); av_opt_set_int(swr_ctx, "out_sample_rate", codec_context->sample_rate, 0); av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); if((ret = swr_init(swr_ctx)) < 0) { fprintf(stderr, "Could not allocate resampler context\n"); return BL_UNEXPECTED; } } // Zero initialize tags song->artist = NULL; song->title = NULL; song->album = NULL; song->tracknumber = NULL; // Initialize tracknumber tag tags_dictionary = av_dict_get(context->metadata, "track", NULL, 0); if (tags_dictionary!= NULL) { song->tracknumber = malloc(strlen(tags_dictionary->value) + 1); strcpy(song->tracknumber, tags_dictionary->value); song->tracknumber[strcspn(song->tracknumber, "/")] = '\0'; } else { song->tracknumber = malloc(1 * sizeof(char)); strcpy(song->tracknumber, ""); } // Initialize title tag tags_dictionary = av_dict_get(context->metadata, "title", NULL, 0); if (tags_dictionary!= NULL) { song->title = malloc(strlen(tags_dictionary->value) + 1); strcpy(song->title, tags_dictionary->value); } else { song->title = malloc(12 * sizeof(char)); strcpy(song->title, "<no title>"); } // Initialize artist tag tags_dictionary = av_dict_get(context->metadata, "ARTIST", NULL, 0); if (tags_dictionary!= NULL) { song->artist= malloc(strlen(tags_dictionary->value) + 1); strcpy(song->artist, tags_dictionary->value); } else { song->artist= malloc(12 * sizeof(char)); strcpy(song->artist, "<no artist>"); } // Initialize album tag tags_dictionary = av_dict_get(context->metadata, "ALBUM", NULL, 0); if (tags_dictionary!= NULL) { song->album= malloc(strlen(tags_dictionary->value) + 1); strcpy(song->album, tags_dictionary->value); } else { song->album= malloc(11 * sizeof(char)); strcpy(song->album, "<no album>"); } // Initialize genre tag tags_dictionary = av_dict_get(context->metadata, "genre", NULL, 0); if (tags_dictionary!= NULL) { song->genre= malloc(strlen(tags_dictionary->value) + 1); strcpy(song->genre, tags_dictionary->value); } else { song->genre = malloc(11 * sizeof(char)); strcpy(song->genre, "<no genre>"); } // Planar means channels are not interleaved is_planar = av_sample_fmt_is_planar(codec_context->sample_fmt); // Read the whole data and copy them into a huge buffer av_init_packet(&avpkt); while(av_read_frame(context, &avpkt) >= 0) { if(avpkt.stream_index == audio_stream) { got_frame = 0; // If decoded frame has not been allocated yet if (!decoded_frame) { // Try to allocate it decoded_frame = av_frame_alloc(); if(!decoded_frame) { fprintf(stderr, "Could not allocate audio frame\n"); return BL_UNEXPECTED; } } else { // Else, unreference it and reset fields av_frame_unref(decoded_frame); } int length = avcodec_decode_audio4(codec_context, decoded_frame, &got_frame, &avpkt); if(length < 0) { avpkt.size = 0; } av_packet_unref(&avpkt); // Copy decoded data into a huge array if(got_frame) { size_t data_size = av_samples_get_buffer_size( NULL, codec_context->channels, decoded_frame->nb_samples, codec_context->sample_fmt, 1); if((index * song->nb_bytes_per_sample + data_size) > size) { int8_t *ptr; ptr = realloc(beginning, size + data_size); if(ptr != NULL) { beginning = ptr; size += data_size; song->nSamples += data_size / song->nb_bytes_per_sample; } else break; } int8_t *p = beginning + (index * song->nb_bytes_per_sample); // If the song isn't in a 16-bit format, convert it to if(song->not_s16 == 1) { uint8_t **out_buffer; int buff_size; buff_size = av_samples_alloc_array_and_samples(&out_buffer, decoded_frame->linesize, song->channels, decoded_frame->nb_samples, AV_SAMPLE_FMT_S16, 0); ret = swr_convert(swr_ctx, out_buffer, buff_size, (const uint8_t**)decoded_frame->extended_data, decoded_frame->nb_samples); if(ret < 0) { fprintf(stderr, "Error while converting from floating-point to int\n"); return BL_UNEXPECTED; } memcpy((index * song->nb_bytes_per_sample) + beginning, out_buffer[0], buff_size); av_freep(&out_buffer[0]); free(out_buffer); index += buff_size / song->nb_bytes_per_sample; } else if(1 == is_planar) { for (int i = 0; i < (decoded_frame->nb_samples * song->nb_bytes_per_sample); i += song->nb_bytes_per_sample) { for (int j = 0; j < codec_context->channels; ++j) { for (int k = 0; k < song->nb_bytes_per_sample; ++k) { *p = ((int8_t*)(decoded_frame->extended_data[j]))[i + k]; ++p; } } } index += data_size / song->nb_bytes_per_sample; } else if (0 == is_planar) { memcpy((index * song->nb_bytes_per_sample) + beginning, decoded_frame->extended_data[0], data_size); index += data_size / song->nb_bytes_per_sample; } } } else { // Dropping packets that do not belong to the audio stream // (such as album cover) av_packet_unref(&avpkt); } } song->sample_array = beginning; // Free memory avpkt.data = NULL; avpkt.size = 0; // Use correct number of samples after decoding song->nSamples = index; // Read the end of audio, as precognized in http://ffmpeg.org/pipermail/libav-user/2015-August/008433.html do { avcodec_decode_audio4(codec_context, decoded_frame, &got_frame, &avpkt); } while(got_frame); // Free memory if(song->not_s16) swr_free(&swr_ctx); avcodec_close(codec_context); av_frame_unref(decoded_frame); # if LIBAVUTIL_VERSION_MAJOR > 51 av_frame_free(&decoded_frame); #endif av_packet_unref(&avpkt); avformat_close_input(&context); return BL_OK; }