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 main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "usage: %s input_file > output_file\n", argv[0]); exit(1); } const int out_channels = 2, out_samples = 512, sample_rate = 44100; const int max_buffer_size = av_samples_get_buffer_size( NULL, out_channels, out_samples, AV_SAMPLE_FMT_FLT, 1); // register supported formats and codecs av_register_all(); // allocate empty format context // provides methods for reading input packets AVFormatContext* fmt_ctx = avformat_alloc_context(); assert(fmt_ctx); // determine input file type and initialize format context if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) != 0) { fprintf(stderr, "error: avformat_open_input()\n"); exit(1); } // determine supported codecs for input file streams and add // them to format context if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { fprintf(stderr, "error: avformat_find_stream_info()\n"); exit(1); } #if 0 av_dump_format(fmt_ctx, 0, argv[1], false); #endif // find audio stream in format context size_t stream = 0; for (; stream < fmt_ctx->nb_streams; stream++) { if (fmt_ctx->streams[stream]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { break; } } if (stream == fmt_ctx->nb_streams) { fprintf(stderr, "error: no audio stream found\n"); exit(1); } // get codec context for audio stream // provides methods for decoding input packets received from format context AVCodecContext* codec_ctx = fmt_ctx->streams[stream]->codec; assert(codec_ctx); if (codec_ctx->channel_layout == 0) { codec_ctx->channel_layout = AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT; } // find decoder for audio stream AVCodec* codec = avcodec_find_decoder(codec_ctx->codec_id); if (!codec) { fprintf(stderr, "error: avcodec_find_decoder()\n"); exit(1); } // initialize codec context with decoder we've found if (avcodec_open2(codec_ctx, codec, NULL) < 0) { fprintf(stderr, "error: avcodec_open2()\n"); exit(1); } // initialize converter from input audio stream to output stream // provides methods for converting decoded packets to output stream SwrContext* swr_ctx = swr_alloc_set_opts(NULL, AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT, // output AV_SAMPLE_FMT_FLT, // output sample_rate, // output codec_ctx->channel_layout, // input codec_ctx->sample_fmt, // input codec_ctx->sample_rate, // input 0, NULL); if (!swr_ctx) { fprintf(stderr, "error: swr_alloc_set_opts()\n"); exit(1); } swr_init(swr_ctx); // create empty packet for input stream AVPacket packet; av_init_packet(&packet); packet.data = NULL; packet.size = 0; // allocate empty frame for decoding AVFrame* frame = av_frame_alloc(); assert(frame); // allocate buffer for output stream uint8_t* buffer = (uint8_t*)av_malloc(max_buffer_size); assert(buffer); // read packet from input audio file while (av_read_frame(fmt_ctx, &packet) >= 0) { // skip non-audio packets if (packet.stream_index != stream) { continue; } // decode packet to frame int got_frame = 0; if (avcodec_decode_audio4(codec_ctx, frame, &got_frame, &packet) < 0) { fprintf(stderr, "error: avcodec_decode_audio4()\n"); exit(1); } if (!got_frame) { continue; } // convert input frame to output buffer int got_samples = swr_convert( swr_ctx, &buffer, out_samples, (const uint8_t **)frame->data, frame->nb_samples); if (got_samples < 0) { fprintf(stderr, "error: swr_convert()\n"); exit(1); } while (got_samples > 0) { int buffer_size = av_samples_get_buffer_size( NULL, out_channels, got_samples, AV_SAMPLE_FMT_FLT, 1); assert(buffer_size <= max_buffer_size); // write output buffer to stdout if (write(STDOUT_FILENO, buffer, buffer_size) != buffer_size) { fprintf(stderr, "error: write(stdout)\n"); exit(1); } // process samples buffered inside swr context got_samples = swr_convert(swr_ctx, &buffer, out_samples, NULL, 0); if (got_samples < 0) { fprintf(stderr, "error: swr_convert()\n"); exit(1); } } // free packet created by decoder av_free_packet(&packet); } av_free(buffer); av_frame_free(&frame); swr_free(&swr_ctx); avcodec_close(codec_ctx); avformat_close_input(&fmt_ctx); return 0; }
int COMXAudioCodecOMX::GetData(BYTE** dst, double &dts, double &pts) { if (!m_bGotFrame) return 0; int inLineSize, outLineSize; /* input audio is aligned */ int inputSize = av_samples_get_buffer_size(&inLineSize, m_pCodecContext->channels, m_pFrame1->nb_samples, m_pCodecContext->sample_fmt, 0); /* output audio will be packed */ int outputSize = av_samples_get_buffer_size(&outLineSize, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1); if (m_iBufferOutputAlloced < m_iBufferOutputUsed + outputSize) { m_pBufferOutput = (BYTE*)av_realloc(m_pBufferOutput, m_iBufferOutputUsed + outputSize + FF_INPUT_BUFFER_PADDING_SIZE); m_iBufferOutputAlloced = m_iBufferOutputUsed + outputSize; } *dst = m_pBufferOutput; /* need to convert format */ if(m_pCodecContext->sample_fmt != m_desiredSampleFormat) { if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels)) { swr_free(&m_pConvert); m_channels = m_pCodecContext->channels; } if(!m_pConvert) { m_iSampleFormat = m_pCodecContext->sample_fmt; m_pConvert = swr_alloc_set_opts(NULL, av_get_default_channel_layout(m_pCodecContext->channels), m_desiredSampleFormat, m_pCodecContext->sample_rate, av_get_default_channel_layout(m_pCodecContext->channels), m_pCodecContext->sample_fmt, m_pCodecContext->sample_rate, 0, NULL); if(!m_pConvert || swr_init(m_pConvert) < 0) { CLog::Log(LOGERROR, "COMXAudioCodecOMX::Decode - Unable to initialise convert format %d to %d", m_pCodecContext->sample_fmt, m_desiredSampleFormat); return 0; } } /* use unaligned flag to keep output packed */ uint8_t *out_planes[m_pCodecContext->channels]; if(av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput + m_iBufferOutputUsed, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 || swr_convert(m_pConvert, out_planes, m_pFrame1->nb_samples, (const uint8_t **)m_pFrame1->data, m_pFrame1->nb_samples) < 0) { CLog::Log(LOGERROR, "COMXAudioCodecOMX::Decode - Unable to convert format %d to %d", (int)m_pCodecContext->sample_fmt, m_desiredSampleFormat); outputSize = 0; } } else { /* copy to a contiguous buffer */ uint8_t *out_planes[m_pCodecContext->channels]; if (av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput + m_iBufferOutputUsed, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 || av_samples_copy(out_planes, m_pFrame1->data, 0, 0, m_pFrame1->nb_samples, m_pCodecContext->channels, m_desiredSampleFormat) < 0 ) { outputSize = 0; } } int desired_size = AUDIO_DECODE_OUTPUT_BUFFER * (m_pCodecContext->channels * GetBitsPerSample()) >> (rounded_up_channels_shift[m_pCodecContext->channels] + 4); if (m_bFirstFrame) { CLog::Log(LOGDEBUG, "COMXAudioCodecOMX::GetData size=%d/%d line=%d/%d buf=%p, desired=%d", inputSize, outputSize, inLineSize, outLineSize, *dst, desired_size); m_bFirstFrame = false; } m_iBufferOutputUsed += outputSize; if (!m_bNoConcatenate && m_pCodecContext->sample_fmt == AV_SAMPLE_FMT_FLTP && m_frameSize && (int)m_frameSize != outputSize) CLog::Log(LOGERROR, "COMXAudioCodecOMX::GetData Unexpected change of size (%d->%d)", m_frameSize, outputSize); m_frameSize = outputSize; // if next buffer submitted won't fit then flush it out if (m_iBufferOutputUsed + outputSize > desired_size || m_bNoConcatenate) { int ret = m_iBufferOutputUsed; m_bGotFrame = false; m_iBufferOutputUsed = 0; dts = m_dts; pts = m_pts; return ret; } return 0; }
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); audioDecoder->PrepareClipPlay(mChannels, mSampleRate, 16, 1); AVFrame *frame = NULL; AVPacket rpacket; av_init_packet(&rpacket); c->channel_layout = c->channel_layout ? c->channel_layout : AV_CH_LAYOUT_STEREO; 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_sample_fmt(swr, "in_sample_fmt", c->sample_fmt, 0); av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); if (( swr_init(swr)) < 0) { Status=DATA_ERR; return Status; } 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); // 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_packet_unref(&rpacket); continue; } AVPacket packet = rpacket; while (packet.size > 0) { int got_frame = 0; if (!frame) { if (!(frame = av_frame_alloc())) { Status=DATA_ERR; break; } } else av_frame_unref(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_packet_unref(&rpacket); } while (*state!=STOP_REQ && Status==OK); audioDecoder->StopClip(); meta_data_valid = false; swr_free(&swr); av_free(outbuf); av_packet_unref(&rpacket); av_frame_free(&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; }
hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample, const uint8_t **samples, int nsamples) { if (resample == NULL) { hb_error("hb_audio_resample: resample is NULL"); return NULL; } if (resample->resample_needed && resample->swresample == NULL) { hb_error("hb_audio_resample: resample needed but libswresample context " "is NULL"); return NULL; } hb_buffer_t *out; int out_size, out_samples; if (resample->resample_needed) { out_size = av_samples_get_buffer_size(NULL, resample->out.channels, nsamples, resample->out.sample_fmt, 0); out = hb_buffer_init(out_size); out_samples = swr_convert(resample->swresample, &out->data, nsamples, samples, nsamples); if (out_samples <= 0) { if (out_samples < 0) hb_log("hb_audio_resample: swr_convert() failed"); // don't send empty buffers downstream (EOF) hb_buffer_close(&out); return NULL; } out->size = (out_samples * resample->out.sample_size * resample->out.channels); } else { out_samples = nsamples; out_size = (out_samples * resample->out.sample_size * resample->out.channels); out = hb_buffer_init(out_size); memcpy(out->data, samples[0], out_size); } /* * Dual Mono to Mono. * * Copy all left or right samples to the first half of the buffer and halve * the buffer size. */ if (resample->dual_mono_downmix) { int ii, jj = !!resample->dual_mono_right_only; int sample_size = resample->out.sample_size; uint8_t *audio_samples = out->data; for (ii = 0; ii < out_samples; ii++) { memcpy(audio_samples + (ii * sample_size), audio_samples + (jj * sample_size), sample_size); jj += 2; } out->size = out_samples * sample_size; } return out; }
u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 finishFlagAddr, u32 remainAddr) { DEBUG_LOG(HLE, "sceAtracDecodeData(%i, %08x, %08x, %08x, %08x)", atracID, outAddr, numSamplesAddr, finishFlagAddr, remainAddr); Atrac *atrac = getAtrac(atracID); u32 ret = 0; if (atrac != NULL) { // We already passed the end - return an error (many games check for this.) if (atrac->currentSample >= atrac->endSample && atrac->loopNum == 0) { Memory::Write_U32(0, numSamplesAddr); Memory::Write_U32(1, finishFlagAddr); Memory::Write_U32(0, remainAddr); ret = ATRAC_ERROR_ALL_DATA_DECODED; } else { // TODO: This isn't at all right, but at least it makes the music "last" some time. u32 numSamples = 0; #ifdef USE_FFMPEG if (atrac->codeType == PSP_MODE_AT_3 && atrac->pCodecCtx) { int forceseekSample = atrac->currentSample * 2 > atrac->endSample ? 0 : atrac->endSample; atrac->SeekToSample(forceseekSample); atrac->SeekToSample(atrac->currentSample); AVPacket packet; int got_frame, ret; while (av_read_frame(atrac->pFormatCtx, &packet) >= 0) { if (packet.stream_index == atrac->audio_stream_index) { got_frame = 0; ret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, &packet); if (ret < 0) { ERROR_LOG(HLE, "avcodec_decode_audio4: Error decoding audio %d", ret); av_free_packet(&packet); break; } if (got_frame) { // got a frame int decoded = av_samples_get_buffer_size(NULL, atrac->pFrame->channels, atrac->pFrame->nb_samples, (AVSampleFormat)atrac->pFrame->format, 1); u8* out = Memory::GetPointer(outAddr); numSamples = atrac->pFrame->nb_samples; ret = swr_convert(atrac->pSwrCtx, &out, atrac->pFrame->nb_samples, (const u8**)atrac->pFrame->extended_data, atrac->pFrame->nb_samples); if (ret < 0) { ERROR_LOG(HLE, "swr_convert: Error while converting %d", ret); } } av_free_packet(&packet); if (got_frame) break; } } } else #endif // USE_FFMPEG { numSamples = atrac->endSample - atrac->currentSample; if (atrac->currentSample >= atrac->endSample) { numSamples = 0; } else if (numSamples > ATRAC_MAX_SAMPLES) { numSamples = ATRAC_MAX_SAMPLES; } if (numSamples == 0 && (atrac->loopNum != 0)) { numSamples = ATRAC_MAX_SAMPLES; } Memory::Memset(outAddr, 0, numSamples * sizeof(s16) * atrac->atracOutputChannels); } Memory::Write_U32(numSamples, numSamplesAddr); // update current sample and decodePos atrac->currentSample += numSamples; atrac->decodePos = atrac->getDecodePosBySample(atrac->currentSample); int finishFlag = 0; if (atrac->loopNum != 0 && (atrac->currentSample >= atrac->loopEndSample || numSamples == 0)) { atrac->currentSample = atrac->loopStartSample; if (atrac->loopNum > 0) atrac->loopNum --; } else if (atrac->currentSample >= atrac->endSample || numSamples == 0) finishFlag = 1; Memory::Write_U32(finishFlag, finishFlagAddr); int remains = atrac->getRemainFrames(); Memory::Write_U32(remains, remainAddr); } // TODO: Can probably remove this after we validate no wrong ids? } else { Memory::Write_U16(0, outAddr); // Write a single 16-bit stereo Memory::Write_U16(0, outAddr + 2); Memory::Write_U32(1, numSamplesAddr); Memory::Write_U32(1, finishFlagAddr); // Lie that decoding is finished Memory::Write_U32(-1, remainAddr); // Lie that decoding is finished } return ret; }
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; 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); } 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; }