天天看點

Windows使用FFmpeg對yuv格式的資料進行crop裁切

一、指令裁切

ffmpeg -pixel_format nv12 -f rawvideo -video_size 240x320 -i nv12_240x320.yuv -vf crop=120:160 -pix_fmt nv12 nv12_120x160.yuv
           

二、代碼裁切,将240x320大小的資料裁切為120x160大小的資料

#include <iostream>
#include <fstream>

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/opt.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"
#include "libavutil/imgutils.h"
};
/*
srcBuffer:源yuv資料
srcWidth:寬
srcHeight:高
dstBuffer:目标buffer
dstWidth:目标寬
dstHeight:目标高
offestX:起始x坐标
offsetY:起始y坐标
format:YUV資料的格式,例如AV_PIX_FMT_NV12 AV_PIX_FMT_NV21 AV_PIX_FMT_YUV420P
*/
int32_t Crop(uint8_t* srcBuffer, uint32_t srcWidth, uint32_t srcHeight,
    uint8_t* dstBuffer, uint32_t dstWidth, uint32_t dstWidth,
    uint32_t offsetX, uint32_t offsetY, AVPixelFormat format) {
    // 建立AVFrame
    AVFrame* srcFrame = av_frame_alloc();
    srcFrame->width = srcWidth;
    srcFrame->height = srcHeight;
    srcFrame->format = format;
    // 填充AVFrame
    av_image_fill_arrays(srcFrame->data, srcFrame->linesize, srcBuffer, format, srcWidth, srcHeight, 1);
    AVFrame* dstFrame = av_frame_alloc();
    // 進行crop
    AVFilterGraph* filterGraph = avfilter_graph_alloc();
    char args[512] = "";
    snprintf(args, sizeof(args),
        "buffer=video_size=%dx%d:pix_fmt=%d:time_base=1/1:pixel_aspect=1/1[in];" // Parsed_buffer_0
        "[in]crop=x=%d:y=%d:out_w=%d:out_h=%d[out];"                             // Parsed_crop_1
        "[out]buffersink",                                                       // Parsed_buffersink_2
        srcWidth, srcHeight, format,
        offsetX, offsetY, dstWidth, dstHeight);

    AVFilterInOut* inputs = NULL;
    AVFilterInOut* outputs = NULL;
    avfilter_graph_parse2(filterGraph, args, &inputs, &outputs);
    avfilter_graph_config(filterGraph, NULL);
    AVFilterContext* srcFilterCtx = avfilter_graph_get_filter(filterGraph, "Parsed_buffer_0");
    AVFilterContext* sinkFilterCtx = avfilter_graph_get_filter(filterGraph, "Parsed_buffersink_2");

    dstFrame = av_frame_clone(srcFrame);
    av_buffersrc_add_frame(srcFilterCtx, dstFrame);
    av_buffersink_get_frame(sinkFilterCtx, dstFrame);
    avfilter_graph_free(&filterGraph);

    // 擷取crop完成後的資料
    avpicture_layout((AVPicture*)dstFrame, format, dstWidth, dstHeight, dstBuffer,
        avpicture_get_size(format, dstWidth, dstHeight));

    av_frame_free(&srcFrame);
    av_frame_free(&dstFrame);
    return 0;
}

int main(void) {
    std::ifstream fin("nv21_240x320.yuv", std::ios::binary | std::ios::in);
    std::ofstream fout("nv21_120x160.yuv", std::ios::binary | std::ios::out);
    uint32_t width = 240;
    uint32_t height = 320;
    uint32_t size = width * height * 3 / 2;
    uint8_t* src_data = new uint8_t[size];
    uint8_t* dest_data = new uint8_t[size / 4];
    while (!fin.eof()) {
        fin.read((char*)src_data, size);
        Crop(src_data, width, height, dest_data, width / 2, height / 2, 0, 0, AV_PIX_FMT_NV21);
        fout.write((char*)dest_data, size / 4);
    }

    delete[] src_data;
    delete[] dest_data;

    fout.close();
    fin.close();
    getchar();
    return 0;
}