使用 FFMpeg for android 解码视频

Posted

技术标签:

【中文标题】使用 FFMpeg for android 解码视频【英文标题】:Decoding Video using FFMpeg for android 【发布时间】:2012-07-04 14:17:43 【问题描述】:

我尝试使用互联网上提供的示例示例中的 FFMpeg 库解码视频,我使用新版本的 ffmpeg 解决了这个问题, 这是我从类文件中调用的代码,

   private static native int decodeVideo(String filename);
   decodeVideo(getString(R.string._sdcard_abc_3gp));

现在在位于 JNI 目录的 .c 文件中,我编写了这段代码,

 jint Java_ru_dzakhov_ffmpeg_test_MainActivity_decodeVideo(JNIEnv* env, jobject
javaThis,jstring filename)    
  AVFormatContext *pFormatCtx;
  int             i, videoStream;
  AVCodecContext  *pCodecCtx;
  AVCodec         *pCodec;
  AVFrame         *pFrame;
  AVFrame         *pFrameRGB;
  AVPacket        packet;
  int             frameFinished;
  int             numBytes;
  uint8_t         *buffer;

  // Register all formats and codecs
  av_register_all();

  // Open video file

      const jbyte *str;
      str = (*env)->GetStringUTFChars(env, filename, NULL);

      if(av_open_input_file(&pFormatCtx, str, NULL, 0, NULL)!=0)
      
          LOGI("Can't open file '%s'\n", str);
          return 1;
      
      else
      
          LOGI("File is opened\n");
          LOGI("File '%s', Codec %s",pFormatCtx->filename,pFormatCtx->iformat->name);
      


  // Dump information about file onto standard error

  LOGI("dump_format");
  dump_format(pFormatCtx, 0, filename, 0);
  LOGI("dump_format DONE");
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
      //if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
      
          LOGI("videoStream:: %d",videoStream);
      videoStream=i;
      break;
    
  if(videoStream==-1)
    return -1; // Didn't find a video stream

  // Get a pointer to the codec context for the video stream
  pCodecCtx=pFormatCtx->streams[videoStream]->codec;

  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  if(pCodec==NULL) 
    fprintf(stderr, "Unsupported codec!\n");
    LOGI("Unsupported codec!\n");
    return -1; // Codec not found
  
  // Open codec
  if(avcodec_open(pCodecCtx, pCodec)<0)
      LOGI("Codec Opened!\n");
    return -1; // Could not open codec
  
  // Allocate video frame
  pFrame=avcodec_alloc_frame();

  // Allocate an AVFrame structure
  pFrameRGB=avcodec_alloc_frame();
  if(pFrameRGB==NULL)

      LOGI("checking --->>> pFrameRGB==NULL\n");
    return -1;
  
  // Determine required buffer size and allocate buffer

  LOGI("Determine required buffer size and allocate buffer\n");
  numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
                              pCodecCtx->height);

  LOGI("numBytes %d",numBytes);

  buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

  // Assign appropriate parts of buffer to image planes in pFrameRGB
  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  // of AVPicture
  avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
                 pCodecCtx->width, pCodecCtx->height);

  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0) 
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream) 
      // Decode video frame
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,&packet);
                           //packet.data, packet.size);

      // Did we get a video frame?
      if(frameFinished) 
        // Convert the image from its native format to RGB
        /*Temporarily down
         *
         * img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24,
                    (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width,pCodecCtx->height);*/

        // Save the frame to phone memory
          LOGI("Saving Frame\n");
         SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, ++i);
         LOGI("After Saving Frame\n");
      
    

    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
  

  // Free the RGB image
  av_free(buffer);
  av_free(pFrameRGB);

  // Free the YUV frame
  av_free(pFrame);

  // Close the codec
  avcodec_close(pCodecCtx);

  // Close the video file
  av_close_input_file(pFormatCtx);

  return 0;

编译代码后,我在日志中得到了这个,

07-04 10:58:38.961: D/dalvikvm(1010): Trying to load lib /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so 0x4051e878
07-04 10:58:38.971: D/dalvikvm(1010): Added shared lib /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so 0x4051e878
07-04 10:58:38.971: D/dalvikvm(1010): No JNI_OnLoad found in /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so 0x4051e878, skipping init
07-04 10:58:39.011: I/System.out(1010): Creating Engine
07-04 10:58:39.011: I/mylib(1010): initiated
07-04 10:58:39.011: I/System.out(1010): Decoding Video
07-04 10:58:39.011: I/System.out(1010): passing video::/sdcard/NativeMedia.ts
07-04 10:58:39.101: W/dalvikvm(231): disableGcForExternalAlloc: false
07-04 10:58:39.121: I/DEBUG(71): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
07-04 10:58:39.121: I/DEBUG(71): Build fingerprint: 'htc_asia_india/htc_icong/icong:2.3.3/GRI40/68450.5:user/release-keys'
07-04 10:58:39.121: I/DEBUG(71): pid: 1010, tid: 1010  >>> ru.dzakhov.ffmpeg.test <<<
07-04 10:58:39.121: I/DEBUG(71): signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 8102de90
07-04 10:58:39.121: I/DEBUG(71):  r0 0000ac28  r1 40521b98  r2 40526340  r3 42157cc8
07-04 10:58:39.121: I/DEBUG(71):  r4 bee7d368  r5 00000004  r6 40521b98  r7 42157c88
07-04 10:58:39.121: I/DEBUG(71):  r8 bee7d348  r9 42157c80  10 42157c6c  fp 42f0f04c
07-04 10:58:39.121: I/DEBUG(71):  ip 8102de91  sp bee7d348  lr 80018378  pc 8102de90  cpsr a0000030
07-04 10:58:39.121: I/DEBUG(71):  d0  4140000041600000  d1  3ff0000041680000
07-04 10:58:39.121: I/DEBUG(71):  d2  bf80000000000000  d3  0000000000000000
07-04 10:58:39.121: I/DEBUG(71):  d4  0000000000000000  d5  3ff000003f800000
07-04 10:58:39.121: I/DEBUG(71):  d6  bff000003f800000  d7  4160000000000000
07-04 10:58:39.121: I/DEBUG(71):  d8  0000000000000000  d9  0000000000000000
07-04 10:58:39.121: I/DEBUG(71):  d10 0000000000000000  d11 0000000000000000
07-04 10:58:39.121: I/DEBUG(71):  d12 0000000000000000  d13 0000000000000000
07-04 10:58:39.121: I/DEBUG(71):  d14 0000000000000000  d15 0000000000000000
07-04 10:58:39.121: I/DEBUG(71):  scr 20000012
07-04 10:58:39.221: I/DEBUG(71):          #00  pc 0002de90  /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so
07-04 10:58:39.221: I/DEBUG(71):          #01  pc 0004f13c  /system/lib/libdvm.so
07-04 10:58:39.221: I/DEBUG(71):          #02  pc 0001d584  /system/lib/libdvm.so
07-04 10:58:39.221: I/DEBUG(71):          #03  pc 00022b8c  /system/lib/libdvm.so
07-04 10:58:39.221: I/DEBUG(71):          #04  pc 00021a80  /system/lib/libdvm.so
07-04 10:58:39.221: I/DEBUG(71):          #05  pc 0006060a  /system/lib/libdvm.so
07-04 10:58:39.221: I/DEBUG(71):          #06  pc 0006828e  /system/lib/libdvm.so
07-04 10:58:39.221: I/DEBUG(71):          #07  pc 0001d584  /system/lib/libdvm.so
07-04 10:58:39.221: I/DEBUG(71):          #08  pc 00022b8c  /system/lib/libdvm.so
07-04 10:58:39.231: I/DEBUG(71):          #09  pc 00021a80  /system/lib/libdvm.so
07-04 10:58:39.231: I/DEBUG(71):          #10  pc 0006045c  /system/lib/libdvm.so
07-04 10:58:39.231: I/DEBUG(71):          #11  pc 0004c430  /system/lib/libdvm.so
07-04 10:58:39.231: I/DEBUG(71):          #12  pc 00037638  /system/lib/libandroid_runtime.so
07-04 10:58:39.231: I/DEBUG(71):          #13  pc 00038456  /system/lib/libandroid_runtime.so
07-04 10:58:39.231: I/DEBUG(71):          #14  pc 00008ca2  /system/bin/app_process
07-04 10:58:39.231: I/DEBUG(71):          #15  pc 00014f24  /system/lib/libc.so
07-04 10:58:39.231: I/DEBUG(71): code around pc:
07-04 10:58:39.231: I/DEBUG(71): 8102de70 003d9cd0 00000408 0029e598 0029e5de 
07-04 10:58:39.231: I/DEBUG(71): 8102de80 0029e5d8 0029e5d8 0029e5cc 0029e5c8 
07-04 10:58:39.231: I/DEBUG(71): 8102de90 4ff0e92d b0994604 f0004615 6823f945 
07-04 10:58:39.231: I/DEBUG(71): 8102dea0 46294620 32a4f8d3 47982200 46044f81 
07-04 10:58:39.231: I/DEBUG(71): 8102deb0 a8172300 22004621 9300447f f9c0f060 
07-04 10:58:39.231: I/DEBUG(71): code around lr:
07-04 10:58:39.231: I/DEBUG(71): 80018358 3497c004 3488c004 3afffff9 e2888004 
07-04 10:58:39.231: I/DEBUG(71): 80018368 eafffff9 e899000c e594c008 e12fff3c 
07-04 10:58:39.231: I/DEBUG(71): 80018378 e3550000 1594c00c 188c0003 e914a3f0 
07-04 10:58:39.231: I/DEBUG(71): 80018388 e1a05e22 e5946004 e3a02000 e4d6c001 
07-04 10:58:39.231: I/DEBUG(71): 80018398 e35c0000 0a000007 e2822001 e35c0044 
07-04 10:58:39.231: I/DEBUG(71): stack:
07-04 10:58:39.231: I/DEBUG(71):     bee7d308  000001b4  
07-04 10:58:39.231: I/DEBUG(71):     bee7d30c  c0000000  
07-04 10:58:39.231: I/DEBUG(71):     bee7d310  80018540  /system/lib/libdvm.so
07-04 10:58:39.231: I/DEBUG(71):     bee7d314  0000cf98  
07-04 10:58:39.231: I/DEBUG(71):     bee7d318  42157c6c  
07-04 10:58:39.231: I/DEBUG(71):     bee7d31c  afd139d9  /system/lib/libc.so
07-04 10:58:39.231: I/DEBUG(71):     bee7d320  0002de91  
07-04 10:58:39.241: I/DEBUG(71):     bee7d324  0000000e  
07-04 10:58:39.241: I/DEBUG(71):     bee7d328  80018540  /system/lib/libdvm.so
07-04 10:58:39.241: I/DEBUG(71):     bee7d32c  00000070  
07-04 10:58:39.241: I/DEBUG(71):     bee7d330  42157c6c  
07-04 10:58:39.241: I/DEBUG(71):     bee7d334  00238100  
07-04 10:58:39.241: I/DEBUG(71):     bee7d338  00000000  
07-04 10:58:39.241: I/DEBUG(71):     bee7d33c  00000000  
07-04 10:58:39.241: I/DEBUG(71):     bee7d340  df002777  
07-04 10:58:39.241: I/DEBUG(71):     bee7d344  e3a070ad  
07-04 10:58:39.241: I/DEBUG(71): #00 bee7d348  423692b4  
07-04 10:58:39.241: I/DEBUG(71):     bee7d34c  0000cf98  
07-04 10:58:39.241: I/DEBUG(71):     bee7d350  40521b98  
07-04 10:58:39.241: I/DEBUG(71):     bee7d354  8102de91  /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so
07-04 10:58:39.241: I/DEBUG(71):     bee7d358  80018540  /system/lib/libdvm.so
07-04 10:58:39.241: I/DEBUG(71):     bee7d35c  0000cf98  
07-04 10:58:39.241: I/DEBUG(71):     bee7d360  bee7d368  
07-04 10:58:39.241: I/DEBUG(71):     bee7d364  800499df  /system/lib/libdvm.so
07-04 10:58:39.241: I/DEBUG(71):     bee7d368  42157c80  
07-04 10:58:39.241: I/DEBUG(71):     bee7d36c  42d58795  
07-04 10:58:39.241: I/DEBUG(71):     bee7d370  8102de91  /data/data/ru.dzakhov.ffmpeg.test/lib/libmylib.so
07-04 10:58:39.241: I/DEBUG(71):     bee7d374  bee7d418  
07-04 10:58:39.241: I/DEBUG(71):     bee7d378  00016de0  
07-04 10:58:39.241: I/DEBUG(71):     bee7d37c  0000ac28  
07-04 10:58:39.241: I/DEBUG(71):     bee7d380  00000001  
07-04 10:58:39.241: I/DEBUG(71):     bee7d384  bee7d418  
07-04 10:58:39.241: I/DEBUG(71):     bee7d388  42157c80  
07-04 10:58:39.241: I/DEBUG(71):     bee7d38c  40521b98  
07-04 10:58:39.241: I/DEBUG(71):     bee7d390  423692b4  
07-04 10:58:39.241: I/DEBUG(71):     bee7d394  800499a1  /system/lib/libdvm.so
07-04 10:58:39.241: I/DEBUG(71):     bee7d398  42157c80  
07-04 10:58:39.241: I/DEBUG(71):     bee7d39c  8004f13f  /system/lib/libdvm.so
07-04 10:58:39.241: I/DEBUG(71): #01 bee7d3a0  00000002  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3a4  0000000e  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3a8  bee7d418  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3ac  0000cf98  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3b0  400198b8  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3b4  42d5861c  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3b8  42157c98  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3bc  bee7d410  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3c0  40521b98  
07-04 10:58:39.251: I/DEBUG(71):     bee7d3c4  8001d588  /system/lib/libdvm.so

无法理解到底是什么问题? 这里使用了 SaveFrame 函数,看起来像,

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) 
  FILE *pFile;
  char szFilename[32];
  int  y;

  // Open file
  LOGI("Opening file!");
  sprintf(szFilename, "frame%d.ppm", iFrame);

  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
    return;

  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
  //LOGI("width::"+width+"Height::"+height);
  // Write pixel data
  for(y=0; y<height; y++)
      LOGI("writing file");
    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
  
  // Close file
  fclose(pFile);

在日志中我没有得到我放在代码中的任何日志!

请帮帮我,

谢谢

【问题讨论】:

groups.google.com/forum/?fromgroups#!topic/android-ndk/… 您的二进制文件可能使用了您的设备不支持的某些指令。请您在android NDK中使用objdump -d,并找出您libmylib.so的地址2de90处的指令是什么? 您应该尝试缩小崩溃位置。尝试在 C 函数的入口处发出第一条日志消息,以查看日志记录是否有效。目前,av_register_allav_open_input_file 等大型 ffmpeg 函数必须在您看到第一条日志消息之前传递。 嗨@drnous,我之前试过但没有结果。 :( 或者你可以使用一些已知可以工作的预编译包,比如JavaCV... 【参考方案1】:

查看导致问题的指令...

$ rasm2 -a arm -d 4ff0e92d stclcs 0, cr15, [r9, #316]!

stc 指令documentation.

搜索它,从用户空间可能无法做到这一点:Getting ILL_ILLOPC (illegal opcode) when trying to execute MRC or MCR instructions on Android

那么,这应该不是你的问题,对吧? :)

尝试仅在本机中打印一些日志消息(或至少在 av_register_all() 之前这样做),不要添加任何其他额外的库,看看你是否做对了。

【讨论】:

【参考方案2】:

我认为您使用不适合 Android 的编译器选项构建 FFmpeg。

我建议关注android-ffmpeg-tutorial,它有适用于 Android 上的 FFmpeg 的工作示例。它也参考了有关为 Android 构建 FFmpeg 的文章。

您可能还想看看更高级的 Android 代码和 FFmpeg 播放器AndroidFFmpeg,即使在 Genymotion 模拟器中也可以正常工作,我测试过。详细说明如何构建,开箱即用。

您的代码使用了已弃用的 FFmpeg 调用,上面链接中的代码已为此更新。

【讨论】:

以上是关于使用 FFMpeg for android 解码视频的主要内容,如果未能解决你的问题,请参考以下文章

[总结]FFMPEG视音频编解码零基础学习方法

[总结]FFMPEG视音频编解码零基础学习方法

[总结]FFMPEG视音频编解码零基础学习方法

FFMPEG视音频编解码零基础学习方法

FFMPEG视音频编解码零基础学习方法

[总结]FFMPEG视音频编解码零基础学习方法