Chinaunix首页 | 论坛 | 博客
  • 博客访问: 523004
  • 博文数量: 86
  • 博客积分: 1076
  • 博客等级: 准尉
  • 技术积分: 1018
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-02 19:15
文章分类

全部博文(86)

文章存档

2013年(15)

2012年(69)

2011年(2)

分类: Android平台

2013-04-29 10:33:49

最近在调试on2的rmvb硬解码,因为demux代码采用的是ffmpeg的,所以就写了个简单的ffmpeg的应用程序,能够看到每一帧的指定字节数,解码后的YUV图片,很基础吧,就当记录一下

  1. /**
  2.  * decode video by ffmpeg-0.8.14 for rv test
  3.  *
  4.  * 2013-04-25
  5.  *    juguofeng
  6.  */

  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>

  10. #include <libavcodec/avcodec.h>
  11. #include <libavformat/avformat.h>


  12. FILE *pfout = NULL;
  13. char ffrvout[128] = { 0 };

  14. /* how many yuv pic you want to save */
  15. #define FRAME_NUM 50
  16. /* enable video demux data save to file */
  17. //#define ENABLE_DEMUX_SAVE
  18. /* enable yuv pic save to file */
  19. #define ENABLE_YUV_SAVE
  20. /* enable print each video bytes */
  21. #define ENABLE_PRINT_FRAME_BYTES
  22. /* how many bytes you want to print */
  23. #define PRINT_BYTES 30

  24. /**
  25.  * save yuv frame
  26.  */
  27. void yuv420p_save(AVFrame *pFrame, AVCodecContext *pCodecCtx)
  28. {
  29.     int i = 0;

  30.     int width = pCodecCtx->width, height = pCodecCtx->height;
  31.     int height_half = height / 2, width_half = width / 2;
  32.     int y_wrap = pFrame->linesize[0];
  33.     int u_wrap = pFrame->linesize[1];
  34.     int v_wrap = pFrame->linesize[2];

  35.     unsigned char *y_buf = pFrame->data[0];
  36.     unsigned char *u_buf = pFrame->data[1];
  37.     unsigned char *v_buf = pFrame->data[2];

  38.     //save y
  39.     for (i = 0; i < height; i++)
  40.         fwrite(y_buf + i * y_wrap, 1, width, pfout);
  41.     //save u
  42.     for (i = 0; i < height_half; i++)
  43.         fwrite(u_buf + i * u_wrap, 1, width_half, pfout);
  44.     //save v
  45.     for (i = 0; i < height_half; i++)
  46.         fwrite(v_buf + i * v_wrap, 1, width_half, pfout);
  47.     fflush(pfout);
  48. }

  49. /**
  50.  * main thread
  51.  */
  52. int main(int argc, char *argv[])
  53. {
  54.     int i;
  55.     char szFileName[128] = {0};
  56.     int decLen = 0;
  57.     int frame = 0;

  58.     AVCodecContext *pCodecCtx = NULL;
  59.     AVFrame *pFrame = NULL;
  60.     AVCodec *pCodec = NULL;
  61.     AVFormatContext *pFormatCtx = NULL;

  62.     if(argc != 3)
  63.     {
  64.         fprintf(stderr, "ERROR:need 3 argument!\n");
  65.         exit(-1);
  66.     }
  67.     
  68.     sprintf(szFileName, "%s", argv[1]);

  69. #ifdef ENABLE_DEMUX_SAVE
  70.     FILE* frvdemux = fopen("rvdemuxout.rm","wb+");
  71.     if (NULL == frvdemux)
  72.     {
  73.         fprintf(stderr, "create rvdemuxout file failed\n");
  74.         exit(1);
  75.     }
  76. #endif

  77.     /* output yuv file name */
  78.     sprintf(ffrvout, "%s", argv[2]);

  79.     pfout = fopen(ffrvout, "wb+");
  80.     if (NULL == pfout)
  81.     {
  82.         printf("create output file failed\n");
  83.         exit(1);
  84.     }
  85.     printf("==========> Begin test ffmpeg call ffmpeg rv decoder\n");
  86.     av_register_all();

  87.     /* Open input video file */
  88.     //printf("before avformat_open_input [%s]\n", szFileName);
  89.     if(avformat_open_input(&pFormatCtx, szFileName, NULL, NULL)!= 0)
  90.     {
  91.         fprintf(stderr, "Couldn't open input file\n");
  92.         return -1;
  93.     }
  94.     //printf("after avformat_open_input\n");

  95.     /* Retrieve stream information */
  96.     if(av_find_stream_info(pFormatCtx) < 0)
  97.     {
  98.         printf("av_find_stream_info ERROR\n");
  99.         return -1;
  100.     }
  101.     //printf("after av_find_stream_info, \n");


  102.     /* Find the first video stream */
  103.     int videoStream = -1;
  104.     printf("==========> pFormatCtx->nb_streams = %d\n", pFormatCtx->nb_streams);

  105.     for(i = 0; i < pFormatCtx->nb_streams; i++) {
  106.         if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  107.             videoStream = i;
  108.             printf("the first video stream index: videoStream = %d\n",videoStream);
  109.             break;
  110.         }
  111.     }

  112.     if(videoStream == -1)
  113.         return -1;        // Didn't find a video stream

  114.     /* Get a pointer to the codec context for the video stream */
  115.     pCodecCtx = pFormatCtx->streams[videoStream]->codec;
  116.     printf("pCodecCtx->codec_id = %d\n", pCodecCtx->codec_id);

  117.     pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
  118.     if(pCodec == NULL) {
  119.         fprintf(stderr, "can not find decoder!\n");
  120.         return -1;
  121.     }

  122.     /* Open codec */
  123.     if(avcodec_open(pCodecCtx, pCodec)<0)
  124.     {
  125.         printf("cannot open software codec\n");
  126.         return -1; // Could not open codec
  127.     }
  128.     printf("==========> Open software codec success\n");

  129.     pFrame = avcodec_alloc_frame();
  130.     if(pFrame == NULL)
  131.     {
  132.         fprintf(stderr, "avcodec_alloc_frame() ERROR\n");
  133.         return -1;
  134.     }
  135.     
  136.     /* flag whether we get a decoded yuv frame */
  137.     int frameFinished;
  138.     int packetno = 0;

  139.     AVPacket packet;
  140.     av_init_packet(&packet);

  141.     while(av_read_frame(pFormatCtx, &packet) >= 0) {
  142.         //printf("[main]avpkt->slice_count=%d\n", packet.sliceNum);

  143.         /* Is this a packet from the video stream? */
  144.         if(packet.stream_index == videoStream) {
  145.             packetno++;
  146. #ifdef ENABLE_PRINT_FRAME_BYTES
  147.         if ( 1 ) {
  148.             int i;
  149.             int size = packet.size < PRINT_BYTES ? packet.size : PRINT_BYTES;
  150.             unsigned char *data = packet.data;
  151.             printf("===>[%5d] [", packet.size);
  152.             for (i = 0; i < size; i++)
  153.                 printf("%02x ", data[i]);
  154.             printf("]\n");
  155.         }
  156. #endif
  157. #ifdef ENABLE_DEMUX_SAVE
  158.             fwrite(packet.data, 1, packet.size, frvdemux);
  159. #endif
  160.             //printf("[the %d packet]packet.size = %d\n", packetno++, packet.size);

  161.             while (packet.size > 0) {
  162.                 decLen = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
  163.                 //printf("[video_decode_example]after avcodec_decode_video2,decoded=%d\n",decLen);

  164.                 if (decLen < 0)    {
  165.                     fprintf(stderr, "[video_decode_example]Error while decoding frame %d\n", frame);
  166.                     //exit(1);
  167.                     /* FIXME if decode one frame err, ignore this frame */
  168.                     decLen = packet.size;
  169.                 }

  170.                 if (frameFinished) {
  171.                     //printf("got a yuv frame\n");
  172.                     //printf(stderr, "[video_decode_example]saving frame %3d\n", frame);

  173.                     /* the picture is allocated by the decoder. no need to free it */
  174.                     if (frame == 1)
  175.                         printf("[video_decode_example]picture->linesize[0]=%d, c->width=%d,c->height=%d\n",
  176.                                 pFrame->linesize[0], pCodecCtx->width, pCodecCtx->height);
  177. #ifdef ENABLE_YUV_SAVE
  178.                     /* save yuv pic */
  179.                     if (frame < FRAME_NUM) {
  180.                         yuv420p_save(pFrame, pCodecCtx);
  181.                     }
  182. #endif
  183.                     /* frame index grow */
  184.                     frame++;
  185.                 }
  186.                 //printf("===========> %d\n", decLen);
  187.                 /* left data in pkt , go on decoding */
  188.                 packet.data += decLen;
  189.                 packet.size -= decLen;
  190.             }
  191.             if (frame == FRAME_NUM) {
  192.                 printf("==========> decoded [%d pkt frames] ---> save [%d YUV frames], enough to stop!\n", packetno, FRAME_NUM);
  193.                 break;
  194.             }
  195.         }

  196.         /* FIXME no need free in this file */
  197.         //printf("free packet that was allocated by av_read_frame\n");
  198.         // Free the packet that was allocated by av_read_frame
  199.         //av_free_packet(&packet);
  200.     }

  201.     printf("decoding job down! begin to free\n");
  202.     /* Free the YUV frame */
  203.     av_free(pFrame);

  204.     /* Close the codec */
  205.     avcodec_close(pCodecCtx);

  206.     /* Close the video file */
  207.     av_close_input_file(pFormatCtx);
  208.     fclose(pfout);

  209.     printf("==========> END-OK\n");

  210.     return 0;
  211. }
再给出Makefile代码

  1. # use pkg-config for getting CFLAGS abd LDFLAGS
  2. FFMPEG_LIBS=libavdevice libavformat libavfilter libavcodec libswscale libavutil
  3. CFLAGS+=$(shell pkg-config --cflags $(FFMPEG_LIBS))
  4. LDFLAGS+=$(shell pkg-config --libs $(FFMPEG_LIBS))

  5. EXAMPLES=ffmpeg-rm-test

  6. OBJS=$(addsuffix .o,$(EXAMPLES))

  7. %: %.o
  8.     $(CC) $< $(LDFLAGS) -o $@

  9. %.o: %.c
  10.     $(CC) $< $(CFLAGS) -c -o $@

  11. .phony: all clean

  12. all: $(OBJS) $(EXAMPLES)

  13. clean:
  14.     rm -rf $(EXAMPLES) $(OBJS)

编译这个程序,需要机子安装ffmpeg的库,最好自己下载一个ffmpeg-0.8分支,或者之后的版本,编译安装到/usr/local/目录下,如果需要的话,环境变量中还需要加上
PKG_CONFIG_PATH和LD_LIBRARY_PATH,不然可能会报找不到ffmpeg的相关库

阅读(5435) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~