FFmpeg 视频转化为bmp图片实例解析

版权声明:本文为博主原创文章,转载请标明出处! https://blog.csdn.net/qq_27396861/article/details/54429716

本文中的函数详细解析可参照:GO>> 我的博客: FFmpeg部分函数解析

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

int dstwidth = 0;     // 生成目标bmp的宽度
int dstheight = 0;    // 生成目标bmp的高度
char bmp_header[54] = { 0 };     // bmp头文件的54个字节

void readHeader(const char* filename)     // 随便用一个bmp,得到bmp文件的头54个字节,并设置宽高度
{
    FILE* fp = fopen(filename, "r");
    fread(bmp_header, 54, 1, fp);
    *(uint32_t*)(bmp_header + 0x0012) = dstwidth;     // 0x0012 指宽度在54个字节的位置
    *(uint32_t*)(bmp_header + 0x0016) = dstheight;
    fclose(fp);
}

void saveBMP(const char* filename, AVFrame* frame)     // 将获取到的数据写入文件(bmp的图片)
{
    if (NULL == filename || NULL == frame)
        return;
    FILE* fp = fopen(filename, "w");

    readHeader("../images/t.bmp");

    fwrite(bmp_header, 54, 1, fp);
    fwrite(frame->data[0], dstwidth * dstheight * 3, 1, fp);

    fclose(fp);
}

int main(int argc, char* argv[])
{
    av_register_all();     // 为了偷懒,一次性注册所有的编码器

    AVFormatContext *avfc = NULL;
    const char* filename = "/home/tuser/test/test.mp4";

    int ret = avformat_open_input(&avfc, filename, NULL, NULL);     // 打开媒体,并得到上下文的结构
    if (ret != 0)
    {
        printf("open input err!\n");
        return 1;
    }

    ret = avformat_find_stream_info(avfc, NULL);     // 读取音频数据并得到相关信息
    if (ret != 0)
    {
        printf("find stream info err!\n");
        return 2;
    }

    int i;
    int audio_stream_info = -1;
    int video_stream_info = -1;
    for (i = 0; i < avfc->nb_streams; ++i)     // 得到音频的句柄 
    {
        AVStream *stream = avfc->streams[i];
        if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            video_stream_info = i;
            printf("video index stream is %d\n", i);
        }
        else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audio_stream_info = i;
            printf("audio index stream is %d\n", i);
        }
        else
        {
            printf("stream is %d, is not audio and video\n", stream->codecpar->codec_type);
        }
    }

    if (video_stream_info == -1)
    {
        printf("not find video_stream_info\n");
        return 3;
    }

    AVCodecContext *avcc =  avfc->streams[video_stream_info]->codec;
    avfc->video_codec = avcodec_find_decoder(avcc->codec_id);     // 查找ffmpeg解码器,用于解码视频
    avcodec_open2(avcc, avfc->video_codec, NULL);     // 初始化音频编解码的AVCodecContext

    dstwidth = avcc->width / 2;     // 将宽度压缩
    dstheight = avcc->height / 2;

     // 转化为bmp格式
    struct SwsContext* swc = sws_getContext(avcc->width, avcc->height, AV_PIX_FMT_YUV420P,
                   dstwidth, dstheight, AV_PIX_FMT_RGB24,
                   SWS_BICUBLIN, NULL, NULL, NULL);

    AVPacket* packet = av_packet_alloc();
    AVFrame* frame = av_frame_alloc();
    AVFrame* rgbFrame = av_frame_alloc();
    uint8_t* data = (uint8_t*)malloc(dstwidth * dstheight * 3);

     // 为已经分配的空间结构体AVPicture挂上一段用于保存数据的空间
    avpicture_fill((AVPicture*)rgbFrame, data, AV_PIX_FMT_RGB24, dstwidth, dstheight);

    while (1)
    {
        if (av_read_frame(avfc, packet) < 0)     // 读取码流中的音频若干帧或者视频一帧
        {
            break;
        }
        if (packet->stream_index != video_stream_info)
        {
            printf("stream index is %d\n", packet->stream_index);
            continue;
        }

        int got = 0;
        avcodec_decode_video2(avcc, frame, &got, packet);     // 解码一帧视频数据 packet-->frame
        if (got == 0)
        {
            printf("frame is not decompress\n");
            continue;
        }

          // 转换像素,(bmp的frame->data中只有第一行有用,所以srcSliceY为0, 不确定。。。)
        sws_scale(swc, frame->data, frame->linesize, 0, avcc->height,
                  rgbFrame->data, rgbFrame->linesize);

          // 写入bmp文件
        static int fileIndex = 0;
        fileIndex++;
        char buf[1024] = { 0 };
        sprintf(buf, "../images/%03d.bmp", fileIndex);
        saveBMP(buf, rgbFrame);
    }

    av_packet_free(&packet);
    av_frame_free(&frame);
    av_frame_free(&rgbFrame);
    avcodec_close(codecCtx);
    avformat_close_input(&fc);

    return 0;
}

Makefile:

all: a.out
a.out: main.c
    gcc main.c -pthread -lavdevice -lavfilter -lswscale -lpostproc -lavformat -lavcodec -lxcb-xfixes -lxcb-render -lxcb-shape -lxcb -lX11 -lasound -lSDL -lx264 -lpthread -ldl -lfaac -lz -lswresample -lavutil -lm -g






猜你喜欢

转载自blog.csdn.net/qq_27396861/article/details/54429716