Reputation: 1316
I'm trying to play audio mp3 file using ffmpeg in android but I'm facing a problem in the below mentioned code
how to play mp3 using ffmpeg
void JNICALL Java_com_music_MainActivity_loadFile(JNIEnv* env, jobject obj,jstring file,jbyteArray array)
{
jboolean isfilenameCopy;
const char * filename = (*env)->GetStringUTFChars(env, file, &isfilenameCopy);
AVCodec *codec;
AVCodecContext *c= NULL;
int out_size, len;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID play = (*env)->GetMethodID(env, cls, "playSound", "([BI)V");//At the begining of your main function
av_init_packet(&avpkt);
printf("Audio decoding\n");
__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, "inside load file");
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(CODEC_ID_MP3);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c= avcodec_alloc_context();
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, "open avcode");
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, "open %s",outbuf);
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, "data =%s and size %d",avpkt.data,avpkt.size);
while (avpkt.size > 0) {
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt);
__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, "length =%d",len);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, " failed length =%d",errno);
exit(1);
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
memcpy(bytes, outbuf, out_size); //
(*env)->ReleaseByteArrayElements(env, array, bytes, 0);
(*env)->CallVoidMethod(env, obj, play, array, out_size);
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
}
i am getting the len = - 1 in
len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt);
what am i doing wrong??
please help
Upvotes: 2
Views: 4690
Reputation: 43
void JNICALL Java_com_music_MainActivity_loadFile(JNIEnv* env, jobject obj,jstring file,jbyteArray array)
{
jboolean isCopy;
int i;
int err;
FILE *f, *outfile;
int audioStream=-1;
int res;
int decoded = 0;
int out_size;
AVFrame *frame = av_frame_alloc();
int got_frame;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID play = (*env)->GetMethodID(env, cls, "playSound", "([BI)V");//At the begining of your main function
const char * szfile = (*env)->GetStringUTFChars(env, file, &isCopy);
LOGI("in load file");
if ((ret = avformat_open_input(&fmt_ctx, szfile, NULL, NULL)) < 0)
{
LOGE("Cannot open input file\n");
}
LOGE("file load %s\n",szfile);
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0)
{
LOGE("Cannot find stream information\n");
}
/* select the audio stream */
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);
if (ret < 0)
{
LOGE("Cannot find a audio stream in the input file\n");
}
// timeBase = (int64_t(aCodecCtx->time_base.num) * AV_TIME_BASE) / int64_t(aCodecCtx->time_base.den);
audio_stream_index = ret;
dec_ctx = fmt_ctx->streams[audio_stream_index]->codec;
av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);
if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0)
{
LOGE("Cannot open audio decoder\n");
}
dec_ctx->sample_fmt =AV_SAMPLE_FMT_S16
dec_ctx->codec_id = AV_CODEC_ID_AAC;
f = fopen(szfile, "rb");
if (!f)
{
LOGE("could not open");
exit(1);
}
// LOGE("time of frame %d",aCodecCtx->time_base.num);
// av_seek_frame();
// timeBase =(aCodecCtx->time_base.num *AV_TIME_BASE)/(aCodecCtx->time_base.den);
// LOGE("time of frame %d",aCodecCtx->time_base.den);
LOGE("time of frame %d",timeBase);
packet.data = inbuf;
packet.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
LOGE("Stage 5");
while (1)
{
if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
break;
if (packet.stream_index == audio_stream_index)
{
avcodec_get_frame_defaults(frame);
got_frame = 0;
ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, &packet);
LOGE("len=%d",ret);
if (ret < 0)
{
LOGE("Error decoding audio\n");
continue;
}
if (got_frame)
{
LOGE("begin frame decode\n");
int data_size = av_samples_get_buffer_size(NULL, dec_ctx->channels,frame->nb_samples,dec_ctx->sample_fmt, 1);
LOGE("after frame decode\n");
jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
memcpy(bytes, frame->data[0], data_size); //
(*env)->ReleaseByteArrayElements(env, array, bytes, 0);
(*env)->CallVoidMethod(env, obj, play, array, data_size);
}
packet.size -= ret;
packet.data += ret;
packet.pts = AV_NOPTS_VALUE;
if (packet.size < AUDIO_REFILL_THRESH)
{
memmove(inbuf, packet.data, packet.size);
packet.data = inbuf;
ret = fread(packet.data + packet.size, 1, AUDIO_INBUF_SIZE - packet.size, f);
if (ret > 0)
packet.size += ret;
}
}
}
av_free_packet(&packet);
}
try this code i done couple of change now its working fine
Upvotes: 4
Reputation: 4815
To correctly read the packet from MP3 file, you have to use the AVFormatContext
structure.
The code should look something like this (This code without the correct completion, error checking, etc.)
AVFormatContext * fCtx = NULL;
if(avformat_open_input(&fCtx, filename, NULL, NULL) < 0)
exit(1);
avformat_find_stream_info(fCtx, NULL);
AVCodec * codec = nullptr;
int strm = av_find_best_stream(fCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
AVCodecContext codecCtx = ctx->streams[strm]->codec;
if (avcodec_open2(codecCtx, codec, nullptr) < 0)
exit(1);
for (;;)
{
AVPacket pkt;
err = av_read_frame(fCtx , &pkt);
if (AVERROR_EOF == err)
break;
if (pkt.stream_index != strm)
continue;
AVFrame frame;
int gotFrame = 0;
int len = avcodec_decode_audio4(codecCtx, &frame, &gotFrame, &pkt)
// or avcodec_decode_audio3 in previous version of ffmpeg, as it is written you.
/// check result and use frame (or buffer in case of avcodec_decode_audio3)
}
Upvotes: 1