1. 程式人生 > >FFMPEG4.0.2版本上讀取RTSP流,截圖儲存。

FFMPEG4.0.2版本上讀取RTSP流,截圖儲存。

網上ffmpeg開發的程式碼很多,但是因為版本介面變化很大,都不知道用什麼介面。找了很多資料和測試,總算有個可以執行的版本了。直接貼程式碼,需要的拿去測試吧。

capturertsp.c檔案

/*
 * read from rtsp,and capture images with FFMPEG4.0.2
 * Only support video decoder, not support audio and subtitle.
 * Created by [email protected]
 */


#include <stdio.h>
#include <windows.h>
#include <wingdi.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> #include <libavutil/imgutils.h> #define SUFFIX_VIDEO "_rawvideo.yuv" #define OUTPUT_VIDEO_SIZE 500*1024*1024 /* 500MB */ static AVFormatContext *fmt_ctx = NULL; static
AVStream *video_stream = NULL; static AVCodec *dec = NULL; static AVCodecContext *video_dec_ctx = NULL; static AVFrame *video_frame = NULL; static AVFrame *pFrameRGB = NULL; static AVPacket pkt; static FILE *dst_video_file = NULL; static int video_stream_index = -1
; void SaveBmp(AVFrame* avPacket, int nWidth, int nHeight, int nBpp,int index) { BITMAPFILEHEADER bmpHeader; bmpHeader.bfType = 0x4d42; bmpHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nWidth * nHeight * 3; bmpHeader.bfReserved1 = 0; bmpHeader.bfReserved2 = 0; bmpHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); BITMAPINFOHEADER bmpInfoHeader; bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); bmpInfoHeader.biWidth = nWidth; bmpInfoHeader.biHeight = nHeight; bmpInfoHeader.biPlanes = 1; bmpInfoHeader.biBitCount = nBpp; bmpInfoHeader.biCompression = BI_RGB; bmpInfoHeader.biSizeImage = (nWidth*nBpp + 31) / 32 * 4 * nHeight; bmpInfoHeader.biXPelsPerMeter = 100; bmpInfoHeader.biYPelsPerMeter = 100; bmpInfoHeader.biClrUsed = 0; bmpInfoHeader.biClrImportant = 0; FILE *fp; //char *filename = new char[255]; char a[255]={}; char *filename = a; //檔案存放路徑,根據自己的修改 sprintf_s(filename, 255, "%s%d.bmp", "F:\\", index); if ((fp = fopen(filename, "wb+")) == NULL){ return; } fwrite(&bmpHeader, sizeof(bmpHeader), 1, fp); fwrite(&bmpInfoHeader, sizeof(bmpInfoHeader), 1, fp); fwrite(avPacket->data[0], nWidth * nHeight * 3, 1, fp); fclose(fp); } int main() { unsigned char *out_buffer; struct SwsContext *img_convert_ctx; // 設定日誌的標準, 高於該標準的將不會被顯示 av_log_set_level(AV_LOG_DEBUG); char src_file_name[] = "rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov"; int ret = avformat_network_init(); /* Open an input stream and read the reader. The codecs are not opened. * The stream must be closed with avformat_close_input().*/ if(avformat_open_input(&fmt_ctx, src_file_name, NULL, NULL) < 0) { printf("Could not open %s\n", src_file_name); return -1; } if(avformat_find_stream_info(fmt_ctx, NULL) < 0) { printf("Could not find stream information\n"); goto END; } /* Open codec for video stream */ ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); if(ret < 0) { printf("Could not find video stream in input file %s\n", src_file_name); goto END; } else { video_stream_index = ret; } video_stream = fmt_ctx->streams[video_stream_index]; dec = avcodec_find_decoder(video_stream->codecpar->codec_id); if(!dec) { printf("Failed to find %s codec\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO)); goto END; } /* Allocate a codec context for the decoder. * The resulting struct should be freed with avcodec_free_context().*/ video_dec_ctx = avcodec_alloc_context3(dec); if(!video_dec_ctx) { printf("Failed to allocate the %s codec context\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO)); goto END; } /* Copy codec parameters from input stream to output codec context */ ret = avcodec_parameters_to_context(video_dec_ctx, video_stream->codecpar); if(ret < 0) { printf("Failed to copy %s codec parameters to decoder context\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO)); goto END; } /* Init the decoders */ ret = avcodec_open2(video_dec_ctx, dec, NULL); if(ret < 0) { printf("Failed to open %s codec\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO)); goto END; } /* Dump information */ printf("----------------------File Info---------------------"); av_dump_format(fmt_ctx, 0, src_file_name, 0); printf("----------------------------------------------------\n"); video_frame = av_frame_alloc(); /* must be freed using av_frame_free(). */ if(!video_frame) { printf("Could not allocate frame\n"); goto END; } pFrameRGB = av_frame_alloc(); if(!pFrameRGB) { printf("Could not allocate pFrameRGB frame\n"); goto END; } /* av_image_get_buffer_size() returns the size in bytes of the amount of data required to store an image with the given parameters. */ out_buffer = (unsigned char *)av_malloc(av_image_get_buffer_size( AV_PIX_FMT_RGB24, video_dec_ctx->width, video_dec_ctx->height, 1)); av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, out_buffer, AV_PIX_FMT_RGB24, video_dec_ctx->width, video_dec_ctx->height, 1); img_convert_ctx = sws_getContext(video_dec_ctx->width, video_dec_ctx->height, video_dec_ctx->pix_fmt, video_dec_ctx->width, video_dec_ctx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); /* Initialize packet, send data to NULL, let the demuxer fill it */ av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; /* Read frames from the file */ int i = 0; while(av_read_frame(fmt_ctx, &pkt) >= 0) { /* The packet must be freed with av_packet_unref() */ if(pkt.stream_index != video_stream_index) { av_packet_unref(&pkt); continue; } ret = avcodec_send_packet(video_dec_ctx, &pkt); if(ret < 0) { av_packet_unref(&pkt); continue; } do { ret = avcodec_receive_frame(video_dec_ctx, video_frame); if(ret < 0) break; else if(ret == 0) { /* Got a frame successfully */ sws_scale(img_convert_ctx, (const unsigned char * const *)video_frame->data, video_frame->linesize, 0, video_dec_ctx->height, pFrameRGB->data, pFrameRGB->linesize); SaveBmp(pFrameRGB, video_dec_ctx->width, video_dec_ctx->height,24, i ++); } else if(ret == AVERROR_EOF) { avcodec_flush_buffers(video_dec_ctx); break; } } while(ret != AVERROR(EAGAIN)); av_packet_unref(&pkt); if(i >= 100) break; } printf("Demuxing succeeded.\n"); END: if(pFrameRGB) av_frame_free(&pFrameRGB); if(video_frame) av_frame_free(&video_frame); if(dst_video_file) fclose(dst_video_file); if(video_dec_ctx) avcodec_free_context(&video_dec_ctx); if(fmt_ctx) avformat_close_input(&fmt_ctx); return 0; }

MakeFile檔案,方便編譯。

CC=gcc
CCFLAGS=-IC:/ffmpeg/include -O2 
LDFLAGS=-LC:/ffmpeg/lib -lavformat -lavfilter -lavcodec -lswresample -lavdevice -lavutil -lswscale -lpostproc -lpthread -lm  -lz 
TARGET=capturertsp
OBJS=capturertsp.o
RM=del
STRIP=strip

$(TARGET):$(OBJS)
    $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS)
#   $(STRIP) $(TARGET)

$(OBJS):%.o:%.c
    $(CC) -c -g $(CCFLAGS) $< -o [email protected]

clean:
    $(RM) $(TARGET) $(OBJS) *~

用mingw32-make就可以編譯了。