FFMPEG4.0.2版本上读取RTSP流,截图保存。

1 篇文章 0 订阅

网上ffmpeg开发的代码很多,但是因为版本接口变化很大,都不知道用什么接口。找了很多资料和测试,总算有个可以执行的版本了。直接贴代码,需要的拿去测试吧。

capturertsp.c文件

/*
 * read from rtsp,and capture images with FFMPEG4.0.2
 * Only support video decoder, not support audio and subtitle.
 * Created by zzacn@163.com
 */


#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>


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 $@

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

用mingw32-make就可以编译了。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值