- 论坛徽章:
- 0
|
- // railgun.c
- // A small sample program that shows how to use libavformat and libavcodec to
- // read video from a file and write frame to a bmp file.
- //
- // Use
- //
- // gcc railgun.c -lavutil -lavformat -lavcodec -lswscale
- //
- // to build (assuming libavformat and libavcodec are correctly installed on
- // your system).
- //
- // Run using
- //
- // ./a.out air.mpg 000130 000132
- //
- // to write frames(00:01:30--00:01:32) from "air.mpg" to disk in BMP
- // format.
- #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);
- 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)
- {
- static AVPacket packet;
- static uint8_t *rawData;
- static int bytesRemaining = 0;
- int bytesDecoded;
- int frameFinished;
- static int firstTimeFlag = 1;
- 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)
- {
- bytesDecoded = avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, rawData, bytesRemaining);
- if (bytesDecoded < 0) return -1;
- bytesRemaining -= bytesDecoded;
- rawData += bytesDecoded;
- if (frameFinished) 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(char strStartTime[], int64_t *pStartSec,
- char strEndTime[], int64_t *pEndSec)
- {
- int64_t starttime = 0, endtime = 0;
- if (strStartTime && pStartSec)
- {
- starttime = atoi(strStartTime);
- *pStartSec = (3600*starttime/10000) + \
- (60*(starttime%10000)/100) + \
- (starttime%100);
- }
- if (strEndTime && pEndSec)
- {
- endtime = atoi(strEndTime);
- *pEndSec = (3600*endtime/10000) + \
- (60*(endtime%10000)/100) + \
- (endtime%100);
- }
- }
- int main(int argc, char *argv[])
- {
- 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;
- static struct SwsContext *img_convert_ctx = NULL;
- // Register all formats and codecs
- av_register_all();
- filename = argv[1];
- // parse begin time and end time
- if (argc == 3)
- ParseTime(argv[2], &startTime, NULL, NULL);
- else if (argc == 4)
- ParseTime(argv[2], &startTime, argv[3], &endTime);
- else
- {
- usage(argv[0]);
- return -1;
- }
- startTime *= AV_TIME_BASE;
- endTime *= AV_TIME_BASE;
-
- // Open video file
- if(av_open_input_file(&ic, filename, NULL, 0, NULL)!=0)
- {
- fprintf(stderr, "Cannt open input file\n");
- usage(argv[0]);
- goto exit_err;
- }
- // Retrieve stream information
- if(av_find_stream_info(ic)<0)
- {
- fprintf(stderr, "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)
- {
- fprintf(stderr, "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)
- {
- fprintf(stderr, "Found no codec\n");
- goto exit_err;
- }
- // Open codec
- if(avcodec_open(dec, codec)<0)
- {
- fprintf(stderr, "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);
- fprintf(stderr, "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);
- fprintf(stderr, "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, dec->width, dec->height, PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
- if (img_convert_ctx == NULL) {
- fprintf(stderr, "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))
- {
- // 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);
- CreateBmpImg(frameRGB, dec->width, dec->height, i);
- }
-
- 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);
- return 0;
- }
复制代码 |
|