1. 程式人生 > >一個純粹的視訊解碼程式(基於FFMPEG 4.0,在Ubuntu 14.04下驗證)

一個純粹的視訊解碼程式(基於FFMPEG 4.0,在Ubuntu 14.04下驗證)

程式功能:
將指定的視訊檔案,解碼為原始YUV資料,只包含視訊流。
開發環境:
Ubuntu 14.04, GCC 4.8.4, FFMPEG 4.0
編譯方法: 
將程式碼copy命名為SimpleDecoder.c,與Makefile放置於同一目錄下,執行 make 即可。
執行方法:
執行 ./mydecoder 視訊路徑,比如 ./mydecoder ~/Videos/xx.mp4,解碼後的檔案儲存在xx.mp4同目錄下,檔名為xx.mp4_rawvideo.yuv。
說明:

解碼後,由於檔案儲存的是YUV原始資料,一個40MB大小的MP4檔案,轉換後可能達到2GB。因此,在程式裡面做了一個大小限制,當轉換後的YUV檔案大小達到500M(巨集控OUTPUT_VIDEO_SIZE)時,即停止轉換。

SimpleDecoder.c:

/*
 * A simple decoder with FFMPEG4.0.
 * Only support video decoder, not support audio and subtitle.
 * Created by [email protected]
 */
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <sys/stat.h>

#define SUFFIX_VIDEO        "_rawvideo.yuv"
#define OUTPUT_VIDEO_SIZE   500*1024*1024    /* 500MB */

static AVFormatContext *fmt_ctx = NULL;
static AVStream        *video_stream = NULL;
static AVCodec         *dec = NULL;
static AVCodecContext  *video_dec_ctx = NULL;
static AVFrame         *video_frame = NULL;
static AVPacket        pkt;
static FILE            *dst_video_file = NULL; 
static int             video_stream_index = -1;

static uint8_t         *video_dst_data[4] = {NULL};
static int             video_dst_linesize[4];
static int             video_dst_bufsize;

static struct stat     file_stat;

int main(int argc, char *argv[])
{
	int ret = 0;
	char *src_file_name = NULL;
	char *dst_video_filename = NULL;
	
	if(argc != 2) {
		printf("e.g. ./mydecoder ~/Videos/xx.mp4 \n");
		return -1;
	}
	
	src_file_name = argv[1];
	dst_video_filename = (char *)malloc(strlen(src_file_name) + strlen(SUFFIX_VIDEO) + 1);  
	if(!dst_video_filename) {
		printf("malloc for dst_video_filename fail.\n");
		return -1;
	}
	strcpy(dst_video_filename, src_file_name);
	strcat(dst_video_filename, SUFFIX_VIDEO);
	
	/* Open an input stream and read the reader. The codecs are not opened.
	 * The stream must be closed with avformat_close_input().*/
	if(avformat_open_input(&fmt_ctx, src_file_name, NULL, NULL) < 0) {
		printf("Could not open %s\n", src_file_name);
		free(dst_video_filename);
		return -1;
	}
	
	if(avformat_find_stream_info(fmt_ctx, NULL) < 0) {
		printf("Could not find stream information\n");
		goto END;
	}
	
	/* Open codec for video stream */
	ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
	if(ret < 0) {
		printf("Could not find video stream in input file %s\n", src_file_name);
		goto END;
	} else {
		video_stream_index = ret;
	}
	
	video_stream = fmt_ctx->streams[video_stream_index];
	dec = avcodec_find_decoder(video_stream->codecpar->codec_id);
	if(!dec) {
		printf("Failed to find %s codec\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
		goto END;
	}
	
	/* Allocate a codec context for the decoder.
	 * The resulting struct should be freed with avcodec_free_context().*/
	video_dec_ctx = avcodec_alloc_context3(dec);
	if(!video_dec_ctx) {
		printf("Failed to allocate the %s codec context\n", 
			av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
		goto END;
	}
	
	/* Copy codec parameters from input stream to output codec context */
	ret = avcodec_parameters_to_context(video_dec_ctx, video_stream->codecpar);
	if(ret < 0) {
		printf("Failed to copy %s codec parameters to decoder context\n",
			av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
		goto END;
	}
	
	/* Init the decoders */
	ret = avcodec_open2(video_dec_ctx, dec, NULL);
	if(ret < 0) {
		printf("Failed to open %s codec\n", av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
		goto END;
	}
	
	/* Dump information */
	printf("----------------------File Info---------------------");
	av_dump_format(fmt_ctx, 0, src_file_name, 0);
	printf("----------------------------------------------------\n");
	
	/* Create a file to store video frame */
	dst_video_file = fopen(dst_video_filename, "wb");
	if(!dst_video_file) {
		printf("Could not open destination file %s\n", dst_video_filename);
		goto END;
	}
	
	/* Allocate image where the decoded image will be put.
	 * The allocated image buffer has to be freed by using av_freep(&pointers[0]). */
	ret = av_image_alloc(video_dst_data, video_dst_linesize, 
			video_dec_ctx->width, video_dec_ctx->height, video_dec_ctx->pix_fmt, 1);
	if(ret < 0) {
		printf("Could not allocate raw video buffer\n");
		goto END;
	}
	video_dst_bufsize = ret;
	
	video_frame = av_frame_alloc();  /* must be freed using av_frame_free(). */
	if(!video_frame) {
		printf("Could not allocate frame\n");
		goto END;
	}
	
	/* Initialize packet, send data to NULL, let the demuxer fill it */
	av_init_packet(&pkt);
	pkt.data = NULL;
	pkt.size = 0;
	
	/* Read frames from the file */
	while(av_read_frame(fmt_ctx, &pkt) >= 0) {  /* The packet must be freed with av_packet_unref() */	
		if(pkt.stream_index != video_stream_index) {
			av_packet_unref(&pkt);
			continue;
		}
			
		ret = avcodec_send_packet(video_dec_ctx, &pkt);
		if(ret < 0) {
			av_packet_unref(&pkt);
			continue;
		}
			
		do {
			ret = avcodec_receive_frame(video_dec_ctx, video_frame);
			if(ret < 0)
				break;
			else if(ret == 0) {  /* Got a frame successfully */
				/* copy decoded frame to destination buffer:
				 * this is required since rawvideo expects non aligned data */
				av_image_copy(video_dst_data, video_dst_linesize,
							(const uint8_t **)(video_frame->data), video_frame->linesize,
							video_dec_ctx->pix_fmt, video_dec_ctx->width, video_dec_ctx->height);

				/* write to rawvideo file */
				fwrite(video_dst_data[0], 1, video_dst_bufsize, dst_video_file);
			} else if(ret == AVERROR_EOF) {
				avcodec_flush_buffers(video_dec_ctx);
				break;
			}
		} while(ret != AVERROR(EAGAIN));

		av_packet_unref(&pkt);

		/* If file size reaches the limitation, stop decoding */
		stat(dst_video_filename, &file_stat);
		if(file_stat.st_size >= OUTPUT_VIDEO_SIZE)
			break;
	}
	
	printf("Demuxing succeeded.\n");
	
	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(video_dec_ctx->pix_fmt), video_dec_ctx->width, video_dec_ctx->height, (char *)dst_video_filename);
	
	
END:
	if(dst_video_filename)
		free(dst_video_filename);
	if(video_dst_data[0])
		av_freep(&video_dst_data[0]);
	if(video_frame)
		av_frame_free(&video_frame);
	if(dst_video_file)
		fclose(dst_video_file);
	if(video_dec_ctx)
		avcodec_free_context(&video_dec_ctx);
	if(fmt_ctx)
		avformat_close_input(&fmt_ctx);
	
	return 0;
}

Makefile:

CC=gcc
CCFLAGS=-I/usr/local/include -O2 
LDFLAGS=-L/usr/local/lib -lavformat -lavfilter -lavcodec -lswresample -lavdevice -lavutil -lswscale -lpostproc -lpthread -lm -lx264 -lx265 -lz -lSDL2
TARGET=mydecoder
OBJS=SimpleDecoder.o
RM=rm -f
STRIP=strip

$(TARGET):$(OBJS)
	$(CC) -o $(TARGET) $(OBJS) $(LDFLAGS)
#	$(STRIP) $(TARGET)

$(OBJS):%.o:%.c
	$(CC) -c -g $(CCFLAGS) $< -o 
[email protected]
clean: $(RM) $(TARGET) $(OBJS) *~

相關推薦

一個純粹視訊解碼程式(基於FFMPEG 4.0Ubuntu 14.04驗證)

程式功能:將指定的視訊檔案,解碼為原始YUV資料,只包含視訊流。開發環境:Ubuntu 14.04, GCC 4.8.4, FFMPEG 4.0編譯方法: 將程式碼copy命名為SimpleDecoder.c,與Makefile放置於同一目錄下,執行 make 即可。執行方法

基於FFmpeg-4.0 SDK的PCM編碼成AAC

1. 初始化 AVCodecContext *m_avctx; AVCodec *m_codec; /* Init ffmpeg log */ ffmpeg_log_callback pcb_log = l

基於ffmpeg-4.0 SDK的音訊重取樣

/* * Copyright (c) 2012 Stefano Sabatini * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and a

基於FFmpeg-4.0 SDK的PCM編碼成AAC

1. 初始化 AVCodecContext *m_avctx; AVCodec *m_codec; /* Init ffmpeg log */ ffmpeg_log_callback

一個簡單的視訊播放器(基於FFMPEG4.0+SDL2.0.8Ubuntu 14.04開發驗證)

昨天那個例子,在 Ubuntu 14.04下播放視訊時,有個問題,有播放幾秒後,畫面就變成黑白的了。剛開始懷疑是UV資料丟失,不過在將YUV資料輸出到檔案,用YUV Player Deluxe播放,畫面色彩正常著。今天在主程式中新起了一個SDL Thread,發現畫面就好了,

OpenStack之安裝4網卡ubuntu-14.04及網絡詳細配置

安裝ubuntu14.04 網絡配置 virtualbox openstack 四個網卡:網絡1:物理機與虛擬機連接,為host-only類型,主要用來管理網絡,它的dhcp off。網絡2:Open vSwitch占用網絡,也是Host-only類型網絡3:OpenStack中有一些存儲組件

帶cuda的opencv2.4.9 in ubuntu 14.04

The latest Long Term Support version of Ubuntu(14.04 LTS) is out and a new version of OpenCV was recently released as well. This means that now is a great

Ubuntu 14.04編譯安裝Vim7.4

原文連線:http://www.linuxidc.com/Linux/2016-04/129774.htm 1、下載Vim74和適合7.4版本的vim-gdb:         如果已經通過軟體中心安裝了vim,則需要將其解除安裝 sudo apt-get r

Ubuntu 14.04搭建Python3.4 + PyQt5.3.2 + Eric6.0開發平臺

引言 找了很多Python GUI工具集,還是覺得PyQt比較理想,功能強大跨平臺,還支援介面設計器。花一天時間折騰了Ubuntu14.04(32位)+ Python3.4 + Qt5.3.2 + PyQt5.3.2 + Eric6.0 的完整開發平臺的搭建,各種出錯差點放

Ubuntu 14.04安裝ffmpeg

最新版本 FFmpeg 2.5.1 已經發布,Ubuntu 14.04、14.10使用者可通過PPA進行安裝,開啟終端,輸入命令: sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next sudo apt-get

ubuntu 14.04 同時安裝OpenCV2.4.8和OpenCV3.2,版本共存切換

  由於實驗室需要用到ROS,在安裝ros-indigo的時候,系統預設安裝了 OpenCV2.4.8版本,直接使用還挺好的。但是,科研需要與時俱進啊,新版的OpenCV3.0以上集成了好多新的功能。比如說,近兩年很火的目標跟蹤演算法KCF、Goturn演算法等,都在Ope

FFmpeg 4.0.2解碼並播放視訊

在上一篇文章中我們知道了如何將FFmpeg4.0.2原始碼編譯成so庫,並且如何在Android Studio中配置並使用so庫,那麼這篇文章我們將介紹如何使用FFmpeg在Android ndk中介面視訊檔案並繪製到螢幕上。 我們先來看下效果一睹為快。 總體

FFmpeg 4.0.2 實現兩個YUV序列拼接成一個YUV序列

一、C++程式碼: /* * 兩個YUV拼接成一個YUV * FFmpeg:4.0.2 */ int YUVCombine(AVFrame *srcFrame1, AVFrame *srcFrame2, AVFrame *dstFrame, int dstWidth, int ds

FFmpeg 4.0.2 實現YUV視訊幀scale大小變換

int YUVFrameScale(AVFrame *srcYUVFrame, int nSrcW, int nSrcH, AVFrame *dstYUVFrame, int nDstW, int nDstH) { // 目標緩衝區 int dst_bufferSize =

FFmpeg 4.0.2 + SDL2-2.0.8 實現H264解碼後播放

一、初級版 功能:實現了簡易視訊播放器的功能,能解碼H264後播放 工具:FFmpeg 4.0.2 + SDL2-2.0.8 C++程式碼: /************************************* 功能:H264解碼為YUV序列,通過SDL播放 FFmpeg:

FFmpeg 4.0.2編碼YUV序列為H264視訊檔案

/****************************** 功能:編碼YUV序列為h264視訊檔案 FFmpeg:4.0.2 ******************************/ #include <iostream> extern "C" { #include &

FFmpeg 4.0.2 解碼h264為YUV

一、FFmpeg 4.0.2解碼h264為YUV的流程如下圖所示: 二、C/C++程式碼: #include <iostream> extern "C" { #include <libavcodec/avcodec.h> #include <libav

手把手教你構建一個視訊程式

歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~ 本文由騰訊視訊雲終端團隊發表於雲+社群專欄 騰訊雲提供了全套技術文件和原始碼來幫助您快速構建一個音視訊小程式,但是再好的原始碼和文件也有學習成本,為了儘快的能除錯起來,我們還提供了一個免費的一鍵部署服務:您只需輕點幾下滑鼠,就可以在自己

Visual Studio使用ffmpeg 4.0 讀取視訊檔案寫入到bmp圖片。

#include <windows.h> #include <stdlib.h> #ifndef _WINGDI_ #define _WINGDI_ typedef struct tagBITMAPFILEHEADER { WORD bf

自己動手編寫一個Linux偵錯程式系列之4 ELF檔案格式與DWARF除錯格式

目錄 在上一節中,你已經聽說了DWARF除錯格式,它是程式的除錯資訊,是一種可以更好理解原始碼的方式,而不只是解析程式。今天我們將討論原始碼級除錯資訊的細節,以準備在本教程後面的部分中使用它。 系列索引 準備工作 斷點的設定 暫存器和記憶體 ELF檔案格式