03ffmpeg编解码实战

一、视频编码

#include <iostream>
using namespace std;

extern "C" {
#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
}

#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")

static int encode(AVCodecContext* ctx, AVFrame* frame, AVPacket* pkt, FILE* out) {
    int ret = -1;

    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to send frame to encoder!\n");
        goto _END;
    }

    while (ret >= 0) {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        }
        else if (ret < 0) {
            return -1; //退出tkyc
        }

        fwrite(pkt->data, 1, pkt->size, out);
        av_packet_unref(pkt);
    }
_END:
    return 0;
}

int main(int argc, char* argv[]) {

    int ret = -1;

    FILE* f = NULL;

    const AVCodec* codec = NULL;
    AVCodecContext* ctx = NULL;

    AVFrame* frame = NULL;
    AVPacket* pkt = NULL;

    av_log_set_level(AV_LOG_DEBUG);

    //1. 输入参数
    char dst[] = "1.h264";
    char codecName[] = "libx264";

    //2. 查找编码器
    codec = avcodec_find_encoder_by_name(codecName);
    if (!codec) {
        av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s", codecName);
        goto _ERROR;
    }

    //3. 创建编码器上下文
    ctx = avcodec_alloc_context3(codec);
    if (!ctx) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n");
        goto _ERROR;
    }

    //4. 设置编码器参数
    ctx->width = 640;
    ctx->height = 480;
    ctx->bit_rate = 500000;

    //ctx->time_base = (AVRational){ 1, 25 };
    ctx->time_base = { 1, 25 };
    ctx->framerate = { 25, 1 };

    ctx->gop_size = 10;
    ctx->max_b_frames = 1;
    ctx->pix_fmt = AV_PIX_FMT_YUV420P;

    if (codec->id == AV_CODEC_ID_H264) {
        av_opt_set(ctx->priv_data, "preset", "slow", 0);
    }

    //5. 编码器与编码器上下文绑定到一起
    ret = avcodec_open2(ctx, codec, NULL);
    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s \n", av_err2str(ret));
        goto _ERROR;
    }

    //6. 创建输出文件
    f = fopen(dst, "wb");
    if (!f) {
        av_log(NULL, AV_LOG_ERROR, "Don't open file:%s", dst);
        goto _ERROR;
    }

    //7. 创建AVFrame
    frame = av_frame_alloc();
    if (!frame) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }
    frame->width = ctx->width;
    frame->height = ctx->height;
    frame->format = ctx->pix_fmt;

    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame \n");
        goto _ERROR;
    }

    //8. 创建AVPacket
    pkt = av_packet_alloc();
    if (!pkt) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    //9. 生成视频内容
    for (int i = 0; i < 25; i++) {
        ret = av_frame_make_writable(frame);
        if (ret < 0) {
            break;
        }

        //Y分量
        for (int y = 0; y < ctx->height; y++) {
            for (int x = 0; x < ctx->width; x++) {
                frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
            }
        }

        //UV分量
        for (int y = 0; y < ctx->height / 2; y++) {
            for (int x = 0; x < ctx->width / 2; x++) {
                frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
                frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
            }
        }

        frame->pts = i;

        //10. 编码
        ret = encode(ctx, frame, pkt, f);
        if (ret == -1) {
            goto _ERROR;
        }
    }
    //10. 编码
    encode(ctx, NULL, pkt, f);
_ERROR:
    //ctx
    if (ctx) {
        avcodec_free_context(&ctx);
    }

    //avframe
    if (frame) {
        av_frame_free(&frame);
    }

    //avpacket
    if (pkt) {
        av_packet_free(&pkt);
    }

    //dst
    if (f) {
        fclose(f);
    }
    return 0;
}

二、音频编码


#include <iostream>
using namespace std;

extern "C" {
#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavutil/samplefmt.h>
#include <libavutil/channel_layout.h>
#include <libavcodec/avcodec.h>

}

#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avformat.lib")

static int select_best_sample_rate(const AVCodec* codec) {
    const int* p;
    int best_samplerate = 0;

    if (!codec->supported_samplerates) {
        return 44100;
    }
    p = codec->supported_samplerates;
    while (*p) {
        if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate)) {
            best_samplerate = *p;
        }
        p++;
    }
    return best_samplerate;
}

static int check_sample_fmt(const AVCodec* codec, enum AVSampleFormat sample_fmt) {
    const enum AVSampleFormat* p = codec->sample_fmts;

    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt) {
            return 1;
        }
        p++;
    }
    return 0;

}

static int encode(AVCodecContext* ctx, AVFrame* frame, AVPacket* pkt, FILE* out) {
    int ret = -1;

    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to send frame to encoder: %s!\n", av_err2str(ret));
        goto _END;
    }

    while (ret >= 0) {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        }
        else if (ret < 0) {
            return -1; //退出tkyc
        }
        av_log(NULL, AV_LOG_DEBUG, "ptk.size:%d\n", pkt->size);
        fwrite(pkt->data, 1, pkt->size, out);
        av_packet_unref(pkt);
    }
_END:
    return 0;
}

int main(int argc, char* argv[]) {

    int ret = -1;

    FILE* f = NULL;

    char* dst = NULL;
    char* codecName = NULL;

    const AVCodec* codec = NULL;
    AVCodecContext* ctx = NULL;

    AVFrame* frame = NULL;
    AVPacket* pkt = NULL;

    uint16_t* samples = NULL;

    av_log_set_level(AV_LOG_DEBUG);

    //1. 输入参数
    if (argc < 2) {
        av_log(NULL, AV_LOG_ERROR, "arguments must be more than 2\n");
        goto _END;
    }

    dst = argv[1];
    //codecName = argv[2];

    //2. 查找编码器
    //codec = avcodec_find_encoder_by_name(codecName);
    codec = avcodec_find_encoder_by_name("libfdk_aac");
    //codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec) {
        av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s", codecName);
        goto _END;
    }

    //3. 创建编码器上下文
    ctx = avcodec_alloc_context3(codec);
    if (!ctx) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n");
        goto _END;
    }

    //4. 设置编码器参数
    ctx->bit_rate = 64000;
    ctx->sample_fmt = AV_SAMPLE_FMT_S16;//AV_SAMPLE_FMT_FLTP
    if (!check_sample_fmt(codec, ctx->sample_fmt)) {
        av_log(NULL, AV_LOG_ERROR, "Encoder does not support sample format!\n");
        goto _END;
    }

    ctx->sample_rate = select_best_sample_rate(codec);
    av_channel_layout_copy(&ctx->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); //AV_CHANNEL_LAYOUT_MONO

    //5. 编码器与编码器上下文绑定到一起
    ret = avcodec_open2(ctx, codec, NULL);
    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s \n", av_err2str(ret));
        goto _END;
    }

    //6. 创建输出文件
    f = fopen(dst, "wb");
    if (!f) {
        av_log(NULL, AV_LOG_ERROR, "Don't open file:%s", dst);
        goto _END;
    }

    //7. 创建AVFrame
    frame = av_frame_alloc();
    if (!frame) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _END;
    }

    frame->nb_samples = ctx->frame_size;
    frame->format = AV_SAMPLE_FMT_S16; //AV_SAMPLE_FMT_FLTP
    av_channel_layout_copy(&frame->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); //AV_CHANNEL_LAYOUT_MONO
    frame->sample_rate = ctx->sample_rate;
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame \n");
        goto _END;
    }

    //8. 创建AVPacket
    pkt = av_packet_alloc();
    if (!pkt) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _END;
    }

    //9. 生成音频内容
    float t = 0;
    float tincr = 4 * M_PI * 440 / ctx->sample_rate;

    for (int i = 0; i < 200; i++) {
        ret = av_frame_make_writable(frame);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Could not allocate space!\n");
            goto _END;
        }

        samples = (uint16_t*)frame->data[0]; //FLTP 32 (uint32_t*)
        for (int j = 0; j < ctx->frame_size; j++) {
            samples[2 * j] = (int)(sin(t) * 10000); //4
            for (int k = 1; k < ctx->ch_layout.nb_channels; k++) {
                samples[2 * j + k] = samples[2 * j]; //4
            }
            t += tincr;
        }
        encode(ctx, frame, pkt, f);
    }
    //10. 编码
    encode(ctx, NULL, pkt, f);

_END:
    //ctx
    if (ctx) {
        avcodec_free_context(&ctx);
    }

    //avframe
    if (frame) {
        av_frame_free(&frame);
    }

    //avpacket
    if (pkt) {
        av_packet_free(&pkt);
    }

    //dst
    if (f) {
        fclose(f);
    }
    return 0;
}

三、生成图片

extern "C" {
#include <stdio.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}


#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"swscale.lib")

#define WORD uint16_t
#define DWORD uint32_t
#define LONG int32_t

#pragma pack(2)
typedef struct tagBITMAPFILEHEADER {
    WORD  bfType;
    DWORD bfSize;
    WORD  bfReserved1;
    WORD  bfReserved2;
    DWORD bfOffBits;
} BITMAPFILEHEADER, * LPBITMAPFILEHEADER, * PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;
    LONG  biWidth;
    LONG  biHeight;
    WORD  biPlanes;
    WORD  biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG  biXPelsPerMeter;
    LONG  biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAPINFOHEADER, * LPBITMAPINFOHEADER, * PBITMAPINFOHEADER;

static void saveBMP(struct SwsContext* swsCtx,
    AVFrame* frame,
    int w,
    int h,
    char* name) {
    FILE* f = NULL;
    int dataSize = w * h * 3;

    //1. 先进行转换,将YUV frame 转成  BGR24 Frame
    AVFrame* frameBGR = av_frame_alloc();
    frameBGR->width = w;
    frameBGR->height = h;
    frameBGR->format = AV_PIX_FMT_BGR24;

    av_frame_get_buffer(frameBGR, 0);

    sws_scale(swsCtx,
        (const uint8_t* const*)frame->data,
        frame->linesize,
        0,
        frame->height,
        frameBGR->data,
        frameBGR->linesize);
    //2. 构造 BITMAPINFOHEADER
    BITMAPINFOHEADER infoHeader;
    infoHeader.biSize = sizeof(BITMAPINFOHEADER);
    infoHeader.biWidth = w;
    infoHeader.biHeight = h * (-1);
    infoHeader.biBitCount = 24;
    infoHeader.biCompression = 0;
    infoHeader.biSizeImage = 0;
    infoHeader.biClrImportant = 0;
    infoHeader.biClrUsed = 0;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biPlanes = 1;

    //3. 构造 BITMAPFILEHEADER
    BITMAPFILEHEADER fileHeader = { 0, };
    fileHeader.bfType = 0x4d42; //'BM'
    fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dataSize;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    //4. 将数据写到文件
    f = fopen(name, "wb");
    fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f);
    fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f);
    fwrite(frameBGR->data[0], 1, dataSize, f);

    //5. 释放资源
    fclose(f);
    av_freep(&frameBGR->data[0]);
    av_free(frameBGR);
}

static void savePic(unsigned char* buf, int linesize, int width, int height, char* name) {
    FILE* f;

    f = fopen(name, "wb");
    fprintf(f, "P5\n%d %d\n%d\n", width, height, 255);
    for (int i = 0; i < height; i++) {
        fwrite(buf + i * linesize, 1, width, f);
    }
    fclose(f);
}

static int decode(AVCodecContext* ctx,
    struct SwsContext* swsCtx,
    AVFrame* frame, AVPacket* pkt,
    const char* fileName) {
    int ret = -1;
    char buf[1024];

    ret = avcodec_send_packet(ctx, pkt);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to send frame to decoder!\n");
        goto _END;
    }

    while (ret >= 0) {
        ret = avcodec_receive_frame(ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        }
        else if (ret < 0) {
            return -1; //退出程序
        }
        snprintf(buf, sizeof(buf), "%s-%d.bmp", fileName, ctx->frame_number);
        saveBMP(swsCtx, frame, 640, 360, buf);
        /*
        savePic(frame->data[0],
                frame->linesize[0],
                frame->width,
                frame->height,
                buf);*/
        if (pkt) {
            av_packet_unref(pkt);
        }

    }
_END:
    return 0;
}

int main(int argc, char* argv[]) {

    int ret = -1;
    int idx = -1;

    //1. 处理一些参数;
    const char* src = "1.mp4";
    const char* dst = "111";

    const AVCodec* codec = NULL;
    AVCodecContext* ctx = NULL;

    AVFormatContext* pFmtCtx = NULL;

    AVStream* inStream = NULL;

    AVFrame* frame = NULL;
    AVPacket* pkt = NULL;

    struct SwsContext* swsCtx = NULL;

    av_log_set_level(AV_LOG_DEBUG);


    //2. 打开多媒体文件
    if ((ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        exit(-1);
    }

    //3. 从多媒体文件中找到视频流
    idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (idx < 0) {
        av_log(pFmtCtx, AV_LOG_ERROR, "Does not include audio stream!\n");
        goto _ERROR;
    }

    inStream = pFmtCtx->streams[idx];

    //4. 查找解码器
    codec = avcodec_find_decoder(inStream->codecpar->codec_id);
    if (!codec) {
        av_log(NULL, AV_LOG_ERROR, "Could not find libx264 Codec");
        goto _ERROR;
    }

    //5. 创建解码器上下文
    ctx = avcodec_alloc_context3(NULL);
    if (!ctx) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n");
        goto _ERROR;
    }

    ret = avcodec_parameters_to_context(ctx, inStream->codecpar);
    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Could not copyt codecpar to codec ctx!\n");
        goto _ERROR;
    }

    //5. 解码器与解码器上下文绑定到一起
    ret = avcodec_open2(ctx, codec, NULL);
    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s \n", av_err2str(ret));
        goto _ERROR;
    }

    //5.1 获得SWS上下文
    swsCtx = sws_getContext(ctx->width,  //src width
        ctx->height, //src height
        AV_PIX_FMT_YUV420P,//src pix fmt
        640,  //dst width
        360, //dst height
        AV_PIX_FMT_BGR24, //dst pix fmt
        SWS_BICUBIC, NULL, NULL, NULL);
    if (!swsCtx) {
        av_log(NULL, AV_LOG_ERROR, "Could not get Swscale Context!\n");
        goto _ERROR;
    }

    //6. 创建AVFrame
    frame = av_frame_alloc();
    if (!frame) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    //7. 创建AVPacket
    pkt = av_packet_alloc();
    if (!pkt) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    //8. 从源多媒体文件中读到视频数据
    while (av_read_frame(pFmtCtx, pkt) >= 0) {
        if (pkt->stream_index == idx) {
            decode(ctx, swsCtx, frame, pkt, dst);
        }
    }
    decode(ctx, swsCtx, frame, NULL, dst);

    //9. 将申请的资源释放掉
_ERROR:
    if (pFmtCtx) {
        avformat_close_input(&pFmtCtx);
        pFmtCtx = NULL;
    }

    if (ctx) {
        avcodec_free_context(&ctx);
        ctx = NULL;
    }

    if (frame) {
        av_frame_free(&frame);
        frame = NULL;
    }

    if (pkt) {
        av_packet_free(&pkt);
        pkt = NULL;
    }

    if (swsCtx) {
        sws_freeContext(swsCtx);
        swsCtx = NULL;
    }

    printf("hello, world!\n");
    return 0;
}

四、生成彩色BMP图片

extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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


#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"swscale.lib")

#define WORD uint16_t
#define DWORD uint32_t
#define LONG int32_t

#pragma pack(2)
typedef struct tagBITMAPFILEHEADER {
    WORD  bfType;
    DWORD bfSize;
    WORD  bfReserved1;
    WORD  bfReserved2;
    DWORD bfOffBits;
} BITMAPFILEHEADER, * PBITMAPFILEHEADER;


typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;
    LONG  biWidth;
    LONG  biHeight;
    WORD  biPlanes;
    WORD  biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG  biXPelsPerMeter;
    LONG  biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAPINFOHEADER, * PBITMAPINFOHEADER;

void saveBMP(struct SwsContext* img_convert_ctx, AVFrame* frame, int w, int h, char* filename)
{
    //1 先进行转换,  YUV420=>RGB24:
    // int w = img_convert_ctx->frame_dst->width;
    // int h = img_convert_ctx->frame_dst->height;

    int data_size = w * h * 3;

    AVFrame* pFrameRGB = av_frame_alloc();

    //avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_BGR24, w, h);
    pFrameRGB->width = w;
    pFrameRGB->height = h;
    pFrameRGB->format = AV_PIX_FMT_BGR24;

    av_frame_get_buffer(pFrameRGB, 0);

    sws_scale(img_convert_ctx,
        (const uint8_t* const*)frame->data,
        frame->linesize,
        0, frame->height, pFrameRGB->data, pFrameRGB->linesize);

    //2 构造 BITMAPINFOHEADER
    BITMAPINFOHEADER header;
    header.biSize = sizeof(BITMAPINFOHEADER);


    header.biWidth = w;
    header.biHeight = h * (-1);
    header.biBitCount = 24;
    header.biCompression = 0;
    header.biSizeImage = 0;
    header.biClrImportant = 0;
    header.biClrUsed = 0;
    header.biXPelsPerMeter = 0;
    header.biYPelsPerMeter = 0;
    header.biPlanes = 1;

    //3 构造文件头
    BITMAPFILEHEADER bmpFileHeader = { 0, };
    //HANDLE hFile = NULL;
    DWORD dwTotalWriten = 0;
    DWORD dwWriten;

    bmpFileHeader.bfType = 0x4d42; //'BM';
    bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + data_size;
    bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    FILE* pf = fopen(filename, "wb");
    fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, pf);
    fwrite(&header, sizeof(BITMAPINFOHEADER), 1, pf);
    fwrite(pFrameRGB->data[0], 1, data_size, pf);
    fclose(pf);


    //释放资源
    //av_free(buffer);
    av_freep(&pFrameRGB[0]);
    av_free(pFrameRGB);
}

static void pgm_save(unsigned char* buf, int wrap, int xsize, int ysize,
    char* filename)
{
    FILE* f;
    int i;

    f = fopen(filename, "w");
    fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
    for (i = 0; i < ysize; i++)
        fwrite(buf + i * wrap, 1, xsize, f);
    fclose(f);
}

static int decode_write_frame(const char* outfilename, AVCodecContext* avctx,
    struct SwsContext* img_convert_ctx, AVFrame* frame, AVPacket* pkt)
{
    int ret = -1;
    char buf[1024];

    ret = avcodec_send_packet(avctx, pkt);
    if (ret < 0) {
        fprintf(stderr, "Error while decoding frame, %s(%d)\n", av_err2str(ret), ret);
        return ret;
    }

    while (ret >= 0) {
        fflush(stdout);

        ret = avcodec_receive_frame(avctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        }
        else if (ret < 0) {
            return -1;
        }

        /* the picture is allocated by the decoder, no need to free it */
        snprintf(buf, sizeof(buf), "%s-%d.bmp", outfilename, avctx->frame_number);
        /*pgm_save(frame->data[0], frame->linesize[0],
                 frame->width, frame->height, buf);*/

        saveBMP(img_convert_ctx, frame, 160, 120, buf);

    }
    return 0;
}

int main(int argc, char** argv)
{
    int ret;
    int idx;

    const char* filename = "1.mp4";
    const char* outfilename = "111";

    AVFormatContext* fmt_ctx = NULL;

    const AVCodec* codec = NULL;
    AVCodecContext* ctx = NULL;

    AVStream* inStream = NULL;

    AVFrame* frame = NULL;
    AVPacket avpkt;

    struct SwsContext* img_convert_ctx;


    /* open input file, and allocate format context */
    if (avformat_open_input(&fmt_ctx, filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open source file %s\n", filename);
        exit(1);
    }

    /* retrieve stream information */
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        exit(1);
    }

    /* dump input information to stderr */
    //av_dump_format(fmt_ctx, 0, filename, 0);

    //av_init_packet(&avpkt);

    /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
    //memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
    //

    idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (idx < 0) {
        fprintf(stderr, "Could not find %s stream in input file '%s'\n",
            av_get_media_type_string(AVMEDIA_TYPE_VIDEO), filename);
        return idx;
    }

    inStream = fmt_ctx->streams[idx];

    /* find decoder for the stream */
    codec = avcodec_find_decoder(inStream->codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "Failed to find %s codec\n",
            av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
        return AVERROR(EINVAL);
    }

    ctx = avcodec_alloc_context3(NULL);
    if (!ctx) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }

    /* Copy codec parameters from input stream to output codec context */
    if ((ret = avcodec_parameters_to_context(ctx, inStream->codecpar)) < 0) {
        fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
            av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
        return ret;
    }

    /* open it */
    if (avcodec_open2(ctx, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }

    img_convert_ctx = sws_getContext(ctx->width, ctx->height,
        ctx->pix_fmt,
        160, 120,
        AV_PIX_FMT_BGR24,
        SWS_BICUBIC, NULL, NULL, NULL);

    if (img_convert_ctx == NULL)
    {
        fprintf(stderr, "Cannot initialize the conversion context\n");
        exit(1);
    }

    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }

    while (av_read_frame(fmt_ctx, &avpkt) >= 0) {
        if (avpkt.stream_index == idx) {
            if (decode_write_frame(outfilename, ctx, img_convert_ctx, frame, &avpkt) < 0)
                exit(1);
        }

        av_packet_unref(&avpkt);
    }

    decode_write_frame(outfilename, ctx, img_convert_ctx, frame, NULL);

    avformat_close_input(&fmt_ctx);

    sws_freeContext(img_convert_ctx);
    avcodec_free_context(&ctx);
    av_frame_free(&frame);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_62594984/article/details/130080321