日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
FFMPEG視頻圖像解封裝解碼

FFMPEG4.0 音頻解碼解封裝
FFMPEG 音頻封裝編碼

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序制作、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了涼州免費(fèi)建站歡迎大家使用!

下面的函數(shù)方法基于最新的FFMPEG 4.0(4.X):
本文講是如何從一個(gè)視頻文件中提取出其中的圖像數(shù)據(jù),并將圖像數(shù)據(jù)保存到文件中。

解碼解封裝的過程與音頻差不多,具體如下:
1.讀取視頻文件的格式信息

    fmt_ctx = avformat_alloc_context();
    avformat_open_input(&fmt_ctx,input,NULL,NULL);
    avformat_find_stream_info(fmt_ctx,NULL);

2.獲取視頻流

    int st_index = av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
    LOGV("st_index = %d\n",st_index);
    AVStream *st = fmt_ctx->streams[st_index];

3.準(zhǔn)備×××與解碼context

    AVCodec *codec = avcodec_find_decoder(st->codecpar->codec_id);
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);

4.拷貝視頻流中的參數(shù)到×××context中并打開×××

    avcodec_parameters_to_context(codec_ctx,st->codecpar);
    avcodec_open2(codec_ctx,codec,NULL);

5.讀取視頻的格式、寬高信息

    int width = codec_ctx->width;
    int height = codec_ctx->height;
    enum AVPixelFormat pixel_fmt = codec_ctx->pix_fmt;

6.申請(qǐng)圖像存儲(chǔ)空間

    uint8_t *dst_buf[4] = {0};
    int      dst_linesize[4];
    int size = av_image_alloc(dst_buf,dst_linesize,width,height,pixel_fmt,1);

7.申明存儲(chǔ)原始數(shù)據(jù)與解碼后數(shù)據(jù)的packet與frame

    AVFrame *frame = av_frame_alloc();
    AVPacket *packet = av_packet_alloc();

8.讀取數(shù)據(jù),只取用視頻數(shù)據(jù)

int ret = av_read_frame(fmt_ctx,packet);
//讀取到的packet不僅僅是圖像數(shù)據(jù),還有音頻、字幕等數(shù)據(jù)。
if(packet->stream_index != st_index)
{
    continue;
}

9.發(fā)送數(shù)據(jù)進(jìn)行解碼
ret = avcodec_send_packet(codec_ctx,packet);
10.接收解碼后的原始數(shù)據(jù),這是個(gè)反復(fù)的過程,一個(gè)packet可能解碼出好幾個(gè)frame

        ret = avcodec_receive_frame(codec_ctx,frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) //packet解碼完了,需要sent
                break;
            if(ret < 0) {
                return 1;
            }

注意:收到的frame可能存在寬高或者fmt格式變化這種情況,后面的流程代碼沒有考慮這種情況(這種奇葩視頻應(yīng)該不會(huì)遇到)

            if(frame->width != width || frame->height != height || frame->format != pixel_fmt)
            {
                LOGV("eeeeeeeeeeeee");
            }

11.把frame中的數(shù)據(jù)拷貝到事先準(zhǔn)備的dst_buf中。二維指針數(shù)組看作一位數(shù)組。
av_image_copy(dst_buf,dst_linesize,frame->data,frame->linesize,pixel_fmt,width,height);
12.把數(shù)據(jù)寫入文件。
fwrite(dst_buf[0],1,size,out_file);

下面貼一段完整的示例代碼,代碼沒有考慮失敗的情況,結(jié)尾沒有搞釋放,也沒有flush×××,示例只是為了掌握整個(gè)核心解碼流程。

/*
 * demuxing_decode_video.c
 *
 *  Created on: 2019年1月8日
 *      Author: deanliu
 */

#include 
#include 
#include 
#include 

static char log_buf[1024*8];
#define LOGV(...) av_log(NULL,AV_LOG_VERBOSE,__VA_ARGS__)

void ffmpeg_log_callback(void* ptr, int level, const char* fmt, va_list vl)
{
    static int print_prefix = 1;
    av_log_format_line(ptr,level,fmt,vl,log_buf,sizeof(log_buf),&print_prefix);
    fprintf(stderr,"%s",log_buf);
}

int main()
{
    av_log_set_callback(ffmpeg_log_callback);

    char *input = "E:/測(cè)試音視頻/12種格式視頻/test.avi";
    char *output = "d:/video.v";

    FILE *out_file = fopen(output,"wb");

    AVFormatContext *fmt_ctx;

    fmt_ctx = avformat_alloc_context();
    avformat_open_input(&fmt_ctx,input,NULL,NULL);
    avformat_find_stream_info(fmt_ctx,NULL);

    int st_index = av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
    LOGV("st_index = %d\n",st_index);
    AVStream *st = fmt_ctx->streams[st_index];

    AVCodec *codec = avcodec_find_decoder(st->codecpar->codec_id);
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);

    avcodec_parameters_to_context(codec_ctx,st->codecpar);
    avcodec_open2(codec_ctx,codec,NULL);

    int width = codec_ctx->width;
    int height = codec_ctx->height;
    enum AVPixelFormat pixel_fmt = codec_ctx->pix_fmt;

    uint8_t *dst_buf[4] = {0};
    int      dst_linesize[4];
    int size = av_image_alloc(dst_buf,dst_linesize,width,height,pixel_fmt,1);

    AVFrame *frame = av_frame_alloc();
    AVPacket *packet = av_packet_alloc();

    while(1)
    {
        LOGV("READ\n");
        int ret = av_read_frame(fmt_ctx,packet);
        if(ret < 0){
            LOGV("ret = %d\n",ret);
            break;
        }
        if(packet->stream_index != st_index)
        {
            continue;
        }
        LOGV("SENT\n");
        ret = avcodec_send_packet(codec_ctx,packet);
        if(ret < 0){
            return 1;
        }

        while(ret >= 0)
        {
            LOGV("receiver\n");
            ret = avcodec_receive_frame(codec_ctx,frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                break;
            if(ret < 0) {
                return 1;
            }
            if(frame->width != width || frame->height != height || frame->format != pixel_fmt)
            {
                LOGV("eeeeeeeeeeeee");
            }
            av_image_copy(dst_buf,dst_linesize,frame->data,frame->linesize,pixel_fmt,width,height);
            LOGV("dst_buf = %d,%d,%d,%d\n",dst_buf[2][0],dst_buf[1][1],dst_buf[0][2],dst_buf[0][3]);
            fwrite(dst_buf[0],1,size,out_file);

        }
    }

    LOGV("dst_linesize = %d,%d,%d,%d\n",dst_linesize[0],dst_linesize[1],dst_linesize[2],size);
    printf("Play the output video file with the command:\n"
           "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
           av_get_pix_fmt_name(pixel_fmt), width, height,
           output);

    LOGV("END!!");

    fclose(out_file);

    return 0;
}

網(wǎng)頁標(biāo)題:FFMPEG視頻圖像解封裝解碼
當(dāng)前鏈接:http://www.dlmjj.cn/article/pesdhi.html