1. 程式人生 > >用ffmpeg提取mp4的h264碼流寫檔案花屏

用ffmpeg提取mp4的h264碼流寫檔案花屏

1、用ffmpeg提取mp4的h264碼流寫檔案的方法網上有很多,不知道的請參考雷神部落格:http://blog.csdn.net/leixiaohua1020/article/details/11800877

2、但是這麼寫出來的檔案是有問題的,首先的確能播放,但是會有很大機率出現花屏

a、首先說說解決方案

其實很簡單,也是利用av_bitstream_filter_filter方法把每個AVPacket處理下,如下:

AVPacket tempPack;
	av_copy_packet(&tempPack, &pkt_in);
	av_bitstream_filter_filter(bsfc, pCodecCtx, NULL, &tempPack.data, &tempPack.size, tempPack.data, tempPack.size, 0);  
	fwrite(tempPack.data,pkt_in.size,1,fp_filter); 
b、再說說原因

在ffmpeg中,一個AVPacket中有可能包含不止一個nal,所以按雷神那麼處理的話,同一個AVPacket中的第二個nal就沒有新增其實標誌00 00 00 01,如果剛好這個nal是其他nal參考的話,那麼就會出現花屏。

c、在說說AVPacket.data中nal是如何儲存的

在AVPacket.data中每個nal沒有起始碼00 00 00 01,其中nal的結構是起始4位元組的nal資料長度(不包括這4位元組),然後才是真正的nal資料。

如下圖:

貼下示例程式碼:

/* 
 *寫Nal測試
 *
 *繆國凱 Mickel
 *[email protected]
 *
 *本程式實現了讀取H264編碼視訊儲存為nal檔案,其中有2種寫法,第一種就是網上常見的在每個AVPacket的data前加nal頭
 *第二種是用filter,此程式把每一個AVPacket都單獨寫成了一個nal,可以做每一幀的nal檔案對比,如果想把所有幀
 *寫成h264碼流檔案,自己改造程式不每幀新開個檔案就好了。
 */

#include "stdafx.h"


#ifdef	__cplusplus
extern "C"
{
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#ifdef __cplusplus
};
#endif

#include <vector>
#include <string>

AVFormatContext *ifmt_ctx = NULL;

#include <stdio.h>
int g_videoIndex = -1;

int openinputfile(const char* filename)
{
	int ret = 0;
	//open the input
	if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0)
	{
		printf("can not open input");
		return ret;
	}
	if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)))
	{
		printf("can not find input stream info");
		return ret;
	}

	//open the decoder
	for (int i = 0; i < ifmt_ctx->nb_streams; i++)
	{
		if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			g_videoIndex = i;
			ret = avcodec_open2(ifmt_ctx->streams[i]->codec, 
				avcodec_find_decoder(ifmt_ctx->streams[i]->codec->codec_id), NULL);

			if (ret < 0)
			{
				printf("can not open decoder");
				return ret;
			}

		}
	}

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	if (argc < 2)
	{
		return -1;
	}
	AVPacket pkt_in, pkt_out;
	AVFrame *frame = NULL;
	unsigned int stream_index;
	av_register_all();

	if (openinputfile(argv[1]) < 0)
	{
		printf("failed to open input file");
		goto end;
	}

	if (g_videoIndex == -1)
	{
		return -1;
	}
	
	FILE *fp_sps=fopen("testNal/testNal/sps.h264","wb+");
	FILE *fp_f_sps=fopen("testNal/testFilterNal/sps.h264","wb+");

	FILE *testMaFp = fopen("testMaual.h264","wb+");
	AVCodecContext *pCodecCtx= ifmt_ctx->streams[g_videoIndex]->codec;
	unsigned char *dummy=NULL;   //輸入的指標
	int dummy_len;
	fwrite(pCodecCtx->extradata,pCodecCtx->extradata_size,1,fp_sps);
	AVBitStreamFilterContext* bsfc =  av_bitstream_filter_init("h264_mp4toannexb");    
	av_bitstream_filter_filter(bsfc, pCodecCtx, NULL, &dummy, &dummy_len, NULL, 0, 0);
	fwrite(pCodecCtx->extradata,pCodecCtx->extradata_size,1,fp_f_sps);
	
	fclose(fp_sps);
	fclose(fp_f_sps);
	
	fwrite(pCodecCtx->extradata,pCodecCtx->extradata_size,1,testMaFp);

	int totol_frame_index = 0;
	while(1)
	{
		if (av_read_frame(ifmt_ctx, &pkt_in) < 0)
		{
			break;
		}
		if (ifmt_ctx->streams[pkt_in.stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			//第一種寫法,在每個frame前加nal頭
			char tmpName[100];
			sprintf(tmpName, "testNal/testNal/frame_%d.h264", totol_frame_index);
			FILE *fp=fopen(tmpName,"wb+");
			if (fp)
			{
				char nal_start[]={0,0,0,1};  
				fwrite(nal_start,4,1,fp);  
				fwrite(pkt_in.data+4,pkt_in.size-4,1,fp);
				fclose(fp);
			}

			//第二種寫法,用av_bitstream_filter_filter
			sprintf(tmpName, "testNal/testFilterNal/frame_%d.h264", totol_frame_index);
			FILE *fp_filter=fopen(tmpName,"wb+");
			if (fp_filter)
			{
				AVPacket tempPack;
				av_copy_packet(&tempPack, &pkt_in);
				av_bitstream_filter_filter(bsfc, pCodecCtx, NULL, &tempPack.data, &tempPack.size, tempPack.data, tempPack.size, 0);  
				fwrite(tempPack.data,pkt_in.size,1,fp_filter); 
				fclose(fp_filter);
			}
			totol_frame_index++;
		}
		continue;
	}

	av_bitstream_filter_close(bsfc);    
	free(dummy); 

	fclose(testMaFp);
end:
	avformat_close_input(&ifmt_ctx);

	getchar();
	return 0;
}


相關推薦

ffmpeg提取mp4的h264檔案

1、用ffmpeg提取mp4的h264碼流寫檔案的方法網上有很多,不知道的請參考雷神部落格:http://blog.csdn.net/leixiaohua1020/article/details/11800877 2、但是這麼寫出來的檔案是有問題的,首先的確能播放,但是會有

java調ffmpeg命令行推遇到的問題

處理 buffere process 占用 調用 .exe 緩沖池 rst proc 1.Java調用命令行,如果沒有額外環境變量,不指定工作路徑,Runtime有兩個方法 public Process exec(String command) public Proces

使用IO檔案的一些騷操作

序言 當需要對檔案進行操作時,使用IO流是不能避免的操作;比如業務中需要儲存一些請求的響應結果中的一些內容。當所需處理的檔案過大時,如果頻繁的關閉檔案流,會造成很大的開銷,何時關閉?往往會造成比較大的困擾。那麼如何才能比較優雅的處理檔案呢? 使用案例 情景 儲存資料時,行與行之間使用回車符隔開;一行的

Java利用JNI呼叫FFMpeg對h264進行解碼

前期配置工作: 使用JNI呼叫: java端: package com.recon.action; public class Decode { public native String loadfile(String s); //

關於JAVA IO檔案數字亂碼的問題

在完成JavaWeb作業時遇到一題是需要持久化儲存登入人數的,題主當時就在Listener裡寫了輸入輸出兩個函式,但是檢查一看發現寫入的數字變成了亂碼(其實不能說是亂碼)。 當時很疑惑就改用瞭如下程式碼: 寫程式碼: File file = new File(PATH);

調FFmpeg SDK對H.264格式的視頻壓縮進行解碼

b- follow 分享圖片 vpd fff proc ofo com 進行 由於作者不習慣該編輯器,只是將本文的截圖貼了出來,詳文見:https://www.yuque.com/docs/share/cce69b1b-b619-44b5-acd1-efa229d8862

使用FFMPEG類庫分離出多媒體檔案中的H 264

                在使用FFMPEG的類庫進行程式設計的過程中,可以直接輸出解複用之後的的視訊資料碼流。只需要在每次呼叫av_read_frame()之後將得到的視訊的AVPacket存為本地檔案即可。經試驗,在分離MPEG2碼流的時候,直接儲存AVPacket即可。在分離H.264碼流的時候,

在MP4檔案提取H264的SPS、PPS及

一、MP4封裝格式的基本概念 1  MP4封裝格式對應標準為 ISO/IEC 14496-12(資訊科技 視聽物件編碼的第12部分: ISO 基本媒體檔案格式/Information technology Coding of audio-visual objects Pa

java中使用檔案輸入檔案輸出進行檔案例!

package com.cfkyit.io; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutp

java檔案輸入輸出,實現複製貼上的方法

java中檔案輸入輸出流是FileInputStream和FileOutputStream,檔案輸入流從檔案系統中的某個檔案中獲得輸入位元組,然後可以用輸出流將資料寫入檔案中。 首先建立兩個流的物件: FileInputStream的構造方法有三種過載方式,常用的是F

FFmpeg總結(十二)ffmpeg與nginx實現直播多路並發播放

xxx 開源 conf ref itl rect arc med rtm 圖:撒哈拉沙漠 下載 nginx 和 nginx-rtmp源碼: http://nginx.org/download/nginx-1.5.10.tar.gz https://github.com/a

反-反爬蟲:幾行代出和人類一樣的動態爬蟲

簽名 lib rgs 常見 todo 只需要 website 結束 pro 歡迎大家前往騰訊雲技術社區,獲取更多騰訊海量技術實踐幹貨哦~ 作者:李大偉 Phantomjs簡介 什麽是Phantomjs Phantomjs官網介紹是:不需要瀏覽器的完整web協議棧(Fu

網站經常需要到的代匯總

log false setfont 初始 設置 chrome 布局 兼容 name 常用視口 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0

java壓縮文件解壓:調WinRAR5命令強於自己實現

成功 cat val value util sub 屬性 eal mon 最近,手上維護著一個幾年前的系統,技術是用的JSP+Strust2,系統提供了rar和zip兩種壓縮格式的解壓功能,後臺是用java實現的 1、解壓rar格式,采用的是java-unrar-0.3.j

147_IO_節點_位元組_檔案讀取_出_追加檔案

檔案的讀取 Test01_InputStream.java package _02.io.byteStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNot

PS解複成H264和音訊(ES提取)

  技術在於交流、溝通,轉載請註明出處並保持作品的完整性。 原文:https://blog.csdn.net/hiwubihe/article/details/80759142   [本系列相關文章] H264和音訊流打包成PS流 (MPEG2-PS

FFmpeg入門-- / 位元速率 / 位元率 / 幀速率 / 解析度 【1】

I、P、B 幀 I 幀(Intracoded frames):I 幀影象採用幀內編碼方式,即只利用了單幀影象內的空間相關性,而沒有利用時間相關性。I 幀使用幀內壓縮,不使用運動補償,由於I 幀不依賴其它幀,所以是隨機存取的入點,同時是解碼的基準幀。I 幀主要用於接收機的初始化和通

FFmpeg In Android - H264解碼/OpenGL ES渲染

主要思路是FFmpeg解碼H264得到一張yuv420p圖片後,傳遞給opengl es在著色器內部做圖片轉換yuv->rgb,然後通過紋理貼圖的方式渲染出來.這種方式的效率更高.核心程式碼如下: #include "common.h" #include "gl_util.h"

FFmpeg In Android - H264解碼/儲存Yuv

本節例子原始碼_NativeH264Android,修改自ffmpeg原始碼目錄/doc/examples/decode_video.c H264的碼流結構 H.264原始碼流(又稱為“裸流”)是由一個一個的NALU組成的,包括I幀,B幀,P幀等等,他們的結構如下圖所示: 其中每個

C++利用一個fstream檔案

原文地址:https://blog.csdn.net/qq_34176290/article/details/80260377 fstream物件可以同時具有ifstream和ofstream的功能,嘗試使用一個流對檔案進行讀寫的程式碼如下: