1. 程式人生 > 其它 >(轉載)ffmpe---實現將視訊儲存為圖片jpg

(轉載)ffmpe---實現將視訊儲存為圖片jpg

原文出自:https://mp.weixin.qq.com/s/z1LXwRVPlDqxn_p3DIFOag

#include <iostream>
#include <stdio.h>
#include <Windows.h>

using namespace std;

extern "C"
{
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswscale/swscale.h"
    #include "libavdevice/avdevice.h
" #include "libavutil/pixfmt.h" } /*================================================================================== * 將AVFrame(YUV420格式)儲存為JPEG格式的圖片 ===================================================================================*/ int SaveAsJPEG(AVFrame* pFrame, int width, int
height, int index) { // 輸出檔案路徑 char out_file[MAX_PATH] = { 0 }; //sprintf_s(out_file, sizeof(out_file), "%s%d.jpg", "E:/QT/test_ffmpegSavePic/ffmpeg/output/", index); sprintf_s(out_file, sizeof(out_file), "%s%d.jpg", "../output/", index); // 分配AVFormatContext物件 AVFormatContext* pFormatCtx = avformat_alloc_context();
// 設定輸出檔案格式 pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL); // 建立並初始化一個和該url相關的AVIOContext if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) { printf("Couldn't open output file."); return -1; } // 構建一個新stream AVStream* pAVStream = avformat_new_stream(pFormatCtx, 0); if (pAVStream == NULL) { return -1; } // 設定該stream的資訊 AVCodecContext* pCodecCtx = pAVStream->codec; pCodecCtx->codec_id = pFormatCtx->oformat->video_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P; pCodecCtx->width = width; pCodecCtx->height = height; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = 25; //列印輸出相關資訊 av_dump_format(pFormatCtx, 0, out_file, 1); //================================== 查詢編碼器 ==================================// AVCodec* pCodec = avcodec_find_encoder(pCodecCtx->codec_id); if (!pCodec) { printf("Codec not found."); return -1; } // 設定pCodecCtx的解碼器為pCodec if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { printf("Could not open codec."); return -1; } //================================Write Header ===============================// avformat_write_header(pFormatCtx, NULL); int y_size = pCodecCtx->width * pCodecCtx->height; //==================================== 編碼 ==================================// // 給AVPacket分配足夠大的空間 AVPacket pkt; av_new_packet(&pkt, y_size * 3); int got_picture = 0; int ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture); if (ret < 0) { printf("Encode Error.\n"); return -1; } if (got_picture == 1) { pkt.stream_index = pAVStream->index; ret = av_write_frame(pFormatCtx, &pkt); } av_free_packet(&pkt); //Write Trailer av_write_trailer(pFormatCtx); //if (pFrame){ // av_frame_unref(pFrame); //} if (pAVStream) { avcodec_close(pAVStream->codec); } avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); return 0; } //沒有完全原始碼,自己修改過的 void FFmpegDemo::on_pictureBtn2_clicked() { //1.FFMPEG初始化操作 av_register_all(); //初始化FFMPEG 呼叫了這個才能正常適用編碼器和解碼器 //=========================== 建立AVFormatContext結構體 ===============================// //分配一個AVFormatContext,FFMPEG所有的操作都要通過這個AVFormatContext來進行 AVFormatContext *pFormatCtx = avformat_alloc_context(); //==================================== 開啟檔案 ======================================// char *file_path = "./2.mp4";//這裡必須使用左斜槓 int ret = avformat_open_input(&pFormatCtx, file_path, NULL, NULL); if (ret != 0) { cout << "open error!" << endl; return ; } //迴圈查詢視訊中包含的流資訊,直到找到視訊型別的流 //便將其記錄下來 儲存到videoStream變數中 int i; int videoStream; //=================================== 獲取視訊流資訊 ===================================// if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { cout << "Could't find stream infomation." << endl; return ; } videoStream = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; } } //如果videoStream為-1 說明沒有找到視訊流 if (videoStream == -1) { cout << "Didn't find a video stream." << endl; return ; } //================================= 查詢解碼器 ===================================// AVCodecContext* pCodecCtx = pFormatCtx->streams[videoStream]->codec; AVCodec* pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == NULL) { cout << "Codec not found." << endl; return ; } //================================ 開啟解碼器 ===================================// if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)// 具體採用什麼解碼器ffmpeg經過封裝 我們無須知道 { cout << "Could not open codec." << endl; return ; } //================================ 設定資料轉換引數 ================================// SwsContext * img_convert_ctx; img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, //源地址長寬以及資料格式 pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUVJ420P, //目的地址長寬以及資料格式 SWS_BICUBIC, NULL, NULL, NULL);//演算法型別 AV_PIX_FMT_YUVJ420P AV_PIX_FMT_BGR24 //==================================== 分配空間 ==================================// //一幀影象資料大小 int numBytes = avpicture_get_size(AV_PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height); unsigned char *out_buffer; out_buffer = (unsigned char *)av_malloc(numBytes * sizeof(unsigned char)); AVFrame * pFrame; pFrame = av_frame_alloc(); AVFrame * pFrameRGB; pFrameRGB = av_frame_alloc(); avpicture_fill((AVPicture *)pFrameRGB, out_buffer, AV_PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height); //會將pFrameRGB的資料按RGB格式自動"關聯"到buffer 即pFrameRGB中的資料改變了 out_buffer中的資料也會相應的改變 //=========================== 分配AVPacket結構體 ===============================// int y_size = pCodecCtx->width * pCodecCtx->height; AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket)); //分配一個packet av_new_packet(packet, y_size); //分配packet的資料 //2.迴圈採集視訊流資料 將其轉換為圖片 //=========================== 讀取視訊資訊 ===============================// int index = 0; //讀取的是一幀視訊 資料存入一個AVPacket的結構中 while (av_read_frame(pFormatCtx, packet) >= 0) { //此時資料儲存在packet中 if (packet && packet->stream_index == videoStream) { //視訊解碼函式 解碼之後的資料儲存在 pFrame中 int got_picture = 0; ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if (ret < 0) { cout << "decode error." << endl; return; } //轉換一幀影象 sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, // pFrameRGB->data, pFrameRGB->linesize); //目的 SaveAsJPEG(pFrameRGB, pCodecCtx->width, pCodecCtx->height, index++); //儲存圖片 } } free(packet); av_frame_free(&pFrameRGB); av_frame_free(&pFrame); avcodec_close(pCodecCtx); avformat_free_context(pFormatCtx); }