在Android上使用FFmpeg播放Mp3文件

时间:2017-04-02 14:21:20

标签: android c ffmpeg android-ndk java-native-interface

这个问题已被问到很多,但没有代码对我有用。我已经能够在Android上播放用ffmpeg解码的文件,但它很吵,很吵。 我在使用最新的ffmpeg版本来解码mp3文件的书中找到了名为“linux sound programming”的书中的代码。 代码尝试将mp3文件解码为pcm,然后将其放入名为output的文件中。 我想要做的是动态解码字节并用Java发送到AudioTrack。

 void JNICALL Java_com_example_home_hellondk_MainActivity_loadFile
        (JNIEnv* env, jobject obj,jstring file,jbyteArray array)
{

 jboolean isfilenameCopy;
         const char * filename = (*env)->GetStringUTFChars(env, file,
                 &isfilenameCopy);
jclass cls = (*env)->GetObjectClass(env, obj);
         jmethodID play = (*env)->GetMethodID(env, cls, "playSound", "([BI)V");
    AVCodec *codec;
    AVCodecContext *c= NULL;
    int len;
    FILE *f, *outfile;
    uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    AVPacket avpkt;
    AVFrame *decoded_frame = NULL;
AVFormatContext* container=NULL;
    av_init_packet(&avpkt);
 int num_streams = 0;
    int sample_size = 0;
    printf("Decode audio file %s \n", filename);
LOGE("Decode audio file %s\n", filename);
    /* find the MPEG audio decoder */
  /*  codec = avcodec_find_decoder(AV_CODEC_ID_MP3);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        LOGE("Codec not found\n");
        exit(1);
    }*/
int lError;
         if ((lError = avformat_open_input(&container, filename, NULL, NULL))
                 != 0) {
             LOGE("Error open source file: %d", lError);
             exit(1);
         }
         if ((lError =  avformat_find_stream_info(container,NULL)) < 0) {
             LOGE("Error find stream information: %d", lError);
             exit(1);
         }
         LOGE("Stage 1.5");
        LOGE("audio format: %s", container->iformat->name);
       LOGE("audio bitrate: %llu", container->bit_rate);

    int stream_id = -1;
        // To find the first audio stream. This process may not be necessary
        // if you can gurarantee that the container contains only the desired
        // audio stream
           LOGE("nb_streams: %d", container->nb_streams);
        int i;
        for (i = 0; i < container->nb_streams; i++) {
            if (container->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
                stream_id = i;
                 LOGE("stream_id: %d", stream_id);
                break;
            }
        }

        AVCodecContext* codec_context = container->streams[stream_id]->codec;
        codec = avcodec_find_decoder(codec_context->codec_id);
         LOGE("stream_id: %d", stream_id);
        LOGE("codec %s", codec->name);
        if (!codec) {
            fprintf(stderr, "codec not found\n");
            exit(1);
        }

    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate audio codec context\n");
          LOGE("Could not allocate audio codec context\n");
        exit(1);
    }

    /* open it */
    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
         LOGE("Could not open codec\n");
        exit(1);
    }

    f = fopen(filename, "rb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        LOGE("Could not open %s\n",filename);
        exit(1);
    }
    const char *outfilename;
 outfile = fopen(outfilename, "wb");
    if (!outfile) {
        av_free(c);
        exit(1);
    }


        avpkt.data = inbuf;
        avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
        LOGE("Stage 5");
    /* decode until eof */

     while (avpkt.size > 0) {
           int got_frame = 0;
           if (!decoded_frame) {
               if (!(decoded_frame = av_frame_alloc())) {
                   fprintf(stderr, "out of memory\n");
                   exit(1);
               }
               } else {
                           av_frame_unref(decoded_frame);
                       }
                       printf("Stream idx %d\n", avpkt.stream_index);
                       len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
                       if (len < 0) {
                           fprintf(stderr, "Error while decoding\n");
                           exit(1);
                       }
                       if (got_frame) {
                           printf("Decoded frame nb_samples %d, format %d\n",
                                  decoded_frame->nb_samples,
                                  decoded_frame->format);
                           if (decoded_frame->data[1] != NULL)
                               printf("Data[1] not null\n");
                           else
                               printf("Data[1] is null\n");
                           /* if a frame has been decoded, output it */
                           int data_size = av_samples_get_buffer_size(NULL, c->channels,
                                                                      decoded_frame->nb_samples,
                                                                      c->sample_fmt, 1);
                           // first time: count the number of  planar streams
                           if (num_streams == 0) {
                               while (num_streams < AV_NUM_DATA_POINTERS &&
                                      decoded_frame->data[num_streams] != NULL)
                                   num_streams++;
                               printf("Number of streams %d\n", num_streams);
                           }
                           // first time: set sample_size from 0 to e.g 2 for 16-bit data
                           if (sample_size == 0) {
                               sample_size =
                                   data_size / (num_streams * decoded_frame->nb_samples);
                           }
                           int m, n;

                           for (n = 0; n < decoded_frame->nb_samples; n++) {
                               // interleave the samples from the planar streams
                               for (m = 0; m < num_streams; m++) {
                                  fwrite(&decoded_frame->data[m][n*sample_size],
                                          1, sample_size, outfile);

                               }
                           }

                /*            jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
                            memcpy(bytes, decoded_frame->data[1], data_size);
                            (*env)->ReleaseByteArrayElements(env, array, bytes, 0);
                           (*env)->CallVoidMethod(env, obj, play, array, data_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);

    avcodec_free_context(&c);
av_frame_free(&decoded_frame);

}

解码的字节在本节中                  fwrite(&decoded_frame->data[m][n*sample_size], 1, sample_size, outfile);

允许您向java发送字节的代码是:

  jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL);
  memcpy(bytes, decoded_frame->data[0], data_size);
 (*env)->ReleaseByteArrayElements(env, array, bytes, 0);
 (*env)->CallVoidMethod(env, obj, play, array, data_size);

我现在已经工作了一个多星期,没有任何对我有用。

提前感谢您的帮助

0 个答案:

没有答案