首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

Linux上MIPS平台交叉编译FFMpeg库 及使用库截取视频中的某一帧

2012-11-23 
Linux下MIPS平台交叉编译FFMpeg库 及使用库截取视频中的某一帧参考http://www.ffmpeg.com.cn网站 一.Linux

Linux下MIPS平台交叉编译FFMpeg库 及使用库截取视频中的某一帧

参考http://www.ffmpeg.com.cn网站

 

一.Linux下MIPS平台交叉编译FFMpeg库:
1.下载ffmpeg库的源代码
(http://sourceforge.net/project/showfiles.php?group_id=205275&package_id=248632):
[root@localhost ffmpeg]# ls
ffmpeg-laster.tar.gz
2.解压:
[root@localhost ffmpeg]# tar zxvf ffmpeg-laster.tar.gz
3.开始配置,并编译:
[root@localhost ffmpeg]# mkdir ffmpeg-release
[root@localhost ffmpeg]# cd ffmpeg
[root@localhost ffmpeg]# ./configure --enable-cross-compile --target-os=linux --cross-prefix=mipsel-linux- --cc=mipsel-linux-gcc --enable-shared --arch=mips --prefix=/opt/brcm/ffmpeg/ffmpeg-release
[root@localhost ffmpeg]# make
[root@localhost ffmpeg]# make install
[root@localhost ffmpeg]# cd ../ffmpeg-release
[root@localhost ffmpeg-release]# tar -zcvf ffjpeg_lib.tar.gz ./lib


板子上运行:
# cp ffjpeg_lib.tar.gz /usr/local/lib/
# cd /usr/local/lib/
# tar -zxvf ffjpeg_lib.tar.gz -C ../
# rm ffjpeg_lib.tar.gz

# cp ffmpeg-release/bin/* /bin/ 
# ffmpeg
FFmpeg version SVN-r21694, Copyright (c) 2000-2010 Fabrice Bellard, et al.
  built on Nov 17 2012 02:25:17 with gcc 4.5.3
  configuration: --enable-cross-compile --target-os=linux --cross-prefix=mipsel-linux- --cc=mipsel-linux-gcc --enable-shared --arch=mips --prefix=/opt/brcm/ffmpeg/ffmpeg-release
  libavutil     50. 9. 0 / 50. 9. 0
  libavcodec    52.52. 0 / 52.52. 0
  libavformat   52.51. 0 / 52.51. 0
  libavdevice   52. 2. 0 / 52. 2. 0
  libswscale     0.10. 0 /  0.10. 0
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

Use -h to get full help or, even better, run 'man ffmpeg'
#

到现在为止, 我们就成功的将 ffmpeg 移植到我们的开发板上了。

 

二.Linux下使用ffmpeg库:
1.命令行使用:
ffmpeg -i test.mp4 -y -f image2 -ss 30 -s 95*95 -vframes 1 a.jpg
找一个MP4文件:test.mp4,然后使用上面的命令就可以取得30秒时视频的图像,保存为
95*95像素的JPG文件。

ffmpeg -i 000094.mp4 -vframes 30 -pix_fmt rgb24  -y -f gif a.gif
把前30帧转化为GIF文件。

2.在程序中调用函数截获视频图片:
首先加入库支持,在我们的可执行程序的Makefile文件中,加入:
CFLAGS += -I/opt/brcm/ffmpeg/ffmpeg-release/include/
LFLAGS += -L/opt/brcm/ffmpeg/ffmpeg-release/lib/ -lavutil -lavformat -lavcodec -lswscale
(记住,后面最后四个参数缺一不可,否则编译不通过)
然后关于在编程中使用FFMPEG库的方法,附带一个成熟的Demo。
(test_snap.c和Makefile)

 

三.遇到的问题:

1.找不到关键帧:first frame is no keyframe: 这样的截图为透明色,不满足截图要求。
解决方案: 跟踪截图函数的返回值,如果no keyframe,将开始时间推迟1秒,再截图,直到成功为止。

 

test_snap.c 如下:

#include <stdlib.h>#include <stdio.h>#include <string.h>#include <math.h>#include <libavformat/avformat.h>#include <libswscale/swscale.h>#undef sprintf#undef uint8_t#undef uint16_t#undef uint32_t#define uint8_t unsigned char#define uint16_t unsigned short#define uint32_t unsigned long#pragma pack(2)typedef struct BMPHeader{    uint16_t identifier;    uint32_t file_size;    uint32_t reserved;    uint32_t data_offset;} BMPHeader;typedef struct BMPMapInfo{    uint32_t header_size;    uint32_t width;    uint32_t height;    uint16_t n_planes;    uint16_t bits_per_pixel;    uint32_t compression;    uint32_t data_size;    uint32_t hresolution;    uint32_t vresolution;    uint32_t n_colors_used;    uint32_t n_important_colors;}BMPMapInfo;int CreateBmpImg(AVFrame *pFrame, int width, int height, int iFrame){    BMPHeader bmpheader;    BMPMapInfo bmpinfo;    FILE *fp;    int y;    char filename[32];        // Open file    memset(filename, 0x0, sizeof(filename));    sprintf(filename, "%d.bmp", iFrame+1);JPRINTF(("Create BMP File : [%s] \n",filename));    fp = fopen(filename, "wb");    if(!fp)return -1;    bmpheader.identifier = ('M'<<8)|'B';    bmpheader.reserved = 0;    bmpheader.data_offset = sizeof(BMPHeader) + sizeof(BMPMapInfo);    bmpheader.file_size = bmpheader.data_offset + width*height*24/8;    bmpinfo.header_size = sizeof(BMPMapInfo);    bmpinfo.width = width;    bmpinfo.height = height;    bmpinfo.n_planes = 1;    bmpinfo.bits_per_pixel = 24;    bmpinfo.compression = 0;    bmpinfo.data_size = height*((width*3 + 3) & ~3);    bmpinfo.hresolution = 0;    bmpinfo.vresolution = 0;    bmpinfo.n_colors_used = 0;    bmpinfo.n_important_colors = 0;    fwrite(&bmpheader,sizeof(BMPHeader),1,fp);    fwrite(&bmpinfo,sizeof(BMPMapInfo),1,fp);    for(y=height-1; y>=0; y--)        fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, fp);    fclose(fp);    return 0;}//解码指定videostream,并保存frame数据到pFrame上//返回: 0--成功,非0--失败int DecodeVideoFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx,     int videoStream, int64_t endtime, AVFrame *pFrame, int *keyframe_err){    static AVPacket packet;    static uint8_t *rawData;    static int bytesRemaining = 0;    int bytesDecoded;    int frameFinished;    static int firstTimeFlag = 1;int snap_cnt=0;*keyframe_err=0;    if (firstTimeFlag)    {        firstTimeFlag = 0;        packet.data = NULL;//第一次解frame,初始化packet.data为null    }    while (1)    {        do         {            if (packet.data == NULL) av_free_packet(&packet); //释放旧的packet            if (av_read_frame(pFormatCtx, &packet) < 0)             {                //从frame读取数据保存到packet上,<0表明到了stream end                printf("-->av_read_frame end\n");                goto exit_decode;            }        } while (packet.stream_index != videoStream); //判断当前frame是否为指定的video stream        //判断当前帧是否到达了endtime,是则返回false,停止取下一帧        if (packet.pts >= endtime) return -1;                bytesRemaining = packet.size;        rawData = packet.data;        while (bytesRemaining > 0)        {        ++snap_cnt;            bytesDecoded = avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, rawData, bytesRemaining);             if (bytesDecoded < 0) return -1;            bytesRemaining -= bytesDecoded;            rawData += bytesDecoded;//          if (frameFinished) return 0;if (frameFinished) {if(snap_cnt<=1) *keyframe_err=1; return 0;}        }    }exit_decode:    bytesDecoded = avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, rawData, bytesRemaining);    if(packet.data != NULL) av_free_packet(&packet);    if (frameFinished != 0) return 0;    return -1;}void usage(const char *function){    printf("Usage: %s [File Name] [Start Time] [End Time]\n", function);    printf("Ex: ./railgun panda.mpg 003005 003010\n");    printf("Time Format: HrsMinsSecs. Ex 003005 means 00 hours 30 minutes 05 senconds\n");    printf("\n");}void ParseTime(IN ulong snap_start_time, int64_t *pStartSec,    IN ulong snap_end_time, int64_t *pEndSec){    int64_t starttime = 0, endtime = 0;    if (pStartSec)    {        starttime = snap_start_time;        *pStartSec = (3600*starttime/10000) + \                (60*(starttime%10000)/100) + \                (starttime%100);    }    if (pEndSec)    {        endtime = snap_end_time;        *pEndSec = (3600*endtime/10000) + \                (60*(endtime%10000)/100) + \                (endtime%100);    }}int __navi_snap_mtv_file(IN char *snap_file_name, IN ulong snap_start_time, IN ulong snap_end_time,IN int snap_w, IN int snap_h){//RINTF(("Open snap_file_name == [%s] \n",snap_file_name));    const char *filename;    AVFormatContext *ic = NULL;    AVCodecContext *dec = NULL;    AVCodec *codec = NULL;    AVFrame *frame = NULL;    AVFrame *frameRGB = NULL;    uint8_t *buffer = NULL;    int numBytes;    int i, videoStream;    int64_t startTime = 0;    int64_t endTime = 0;int keyframe_err=0;    static struct SwsContext *img_convert_ctx = NULL;    // Register all formats and codecs    av_register_all();    filename = snap_file_name;    // parse begin time and end time    ParseTime(snap_start_time, &startTime, NULL, NULL);    ParseTime(snap_start_time, &startTime, snap_end_time, &endTime);    startTime *= AV_TIME_BASE;    endTime *= AV_TIME_BASE;        // Open video file    if(av_open_input_file(&ic, filename, NULL, 0, NULL)!=0)    {        printf("Cannt open input file\n");        goto exit_err;    }    // Retrieve stream information    if(av_find_stream_info(ic)<0)    {        printf("Cannt find stream info\n");        goto exit_err;    }    // Dump information about file onto standard error    dump_format(ic, 0, filename, 0);    // Find the first video stream    videoStream=-1;    for(i=0; i<ic->nb_streams; i++)        if(ic->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)        {            videoStream=i;            break;        }    if(videoStream==-1)    {        printf("No video stream\n");        goto exit_err;    }    // Get a pointer to the codec context for the video stream    dec=ic->streams[videoStream]->codec;    // Find the decoder for the video stream    codec=avcodec_find_decoder(dec->codec_id);    if(codec==NULL)    {        printf("Found no codec\n");        goto exit_err;    }    // Open codec    if(avcodec_open(dec, codec)<0)    {        printf("Cannt open avcodec\n");        goto exit_err;     }    // Allocate video frame    frame=avcodec_alloc_frame();    // Allocate an AVFrame structure    frameRGB=avcodec_alloc_frame();    if(frameRGB==NULL)    {        av_free(frame);        printf("Cannt alloc frame buffer for RGB\n");        goto exit_err;    }    // Determine required buffer size and allocate buffer    numBytes=avpicture_get_size(PIX_FMT_RGB24, dec->width, dec->height);    buffer=(uint8_t *)av_malloc(numBytes);    if (!buffer)     {        av_free(frame);        av_free(frameRGB);        printf("Cannt alloc picture buffer\n");        goto exit_err;    }    // Assign appropriate parts of buffer to image planes in pFrameRGB    avpicture_fill((AVPicture *)frameRGB, buffer, PIX_FMT_RGB24, dec->width, dec->height);    img_convert_ctx = sws_getContext(dec->width, dec->height, dec->pix_fmt, snap_w, snap_h, PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);    if (img_convert_ctx == NULL) {        printf("Cannot initialize the conversion context\n");        goto exit_err;    }    // Seek frame    startTime = av_rescale_q(startTime, AV_TIME_BASE_Q, ic->streams[videoStream]->time_base);    endTime = av_rescale_q(endTime, AV_TIME_BASE_Q, ic->streams[videoStream]->time_base);    avformat_seek_file(ic, videoStream, INT64_MIN, startTime, startTime, 0);    // Read frames and save first five frames to dist    i=0;    while(!DecodeVideoFrame(ic, dec, videoStream, endTime, frame, &keyframe_err))    {        // Save the frame to disk        i++;        sws_scale(img_convert_ctx, (AVPicture*)frame->data, (AVPicture*)frame->linesize,            0, dec->height, (AVPicture*)frameRGB->data, (AVPicture*)frameRGB->linesize);   if(0 == CreateBmpImg(frameRGB, snap_w, snap_h, i))        {break;// get one bmp file, we jump out; if you want get more bmp file, clear this line.        }    }exit_err:    // Free the RGB image    if (buffer)        av_free(buffer);    if (frameRGB)        av_free(frameRGB);    // Free the YUV frame    if (frame)        av_free(frame);    // Close the codec    if (dec)        avcodec_close(dec);    // Close the video file    if (ic)        av_close_input_file(ic);    if (img_convert_ctx)        sws_freeContext(img_convert_ctx);if(keyframe_err==1)// if first frame is no keyframe.return -1;else    return 0;}

 

解决关键帧的代码:

if(-1 == __navi_snap_mtv_file(pXPlayTempFileName,000050,000130,96,96)){// if first frame is no keyframe.int ret=-1;for(i=0; i<30; ++i){if(0==ret) break;ret = __navi_snap_mtv_file(pXPlayTempFileName,000050+i,000130,96,96);}}



Makefile 如下:

CC = mipsel-linux-gccTARGET = test_snapCFLAGS += -I/opt/ffmpeg/ffmpeg-release/include/ LFLAGS += -L/opt/ffmpeg/ffmpeg-release/lib/ -lavutil -lavformat -lavcodec -lswscale$(TARGET):$(CC) -o  $(TARGET) test_snap.c $(LFLAGS) $(CFLAGS)


 

附带几个我自己看过的网站:

http://ray.imiddle.net/2008/10/ffmpeg-install-and-usage/

http://blog.csdn.net/menuconfig/article/details/2600890

http://bbs.chinaunix.net/thread-1932536-1-1.html

 

OK,今天就这多,去找女朋友了,老板可是催的很急的说... O(∩_∩)O哈哈~

 

 

热点排行