1. 程式人生 > >ffmpeg系列之兩種視訊解碼方式

ffmpeg系列之兩種視訊解碼方式

方式一:

#include "myplayer.h"
#include <QtWidgets/QApplication>
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
extern "C"{
#include <libavformat/avformat.h>
}
static double r2d(AVRational r){
	return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}
int main(int argc, char *argv[])
{
	av_register_all();
	char *path = "test.mp4";
	AVFormatContext *ac = NULL;
	int re = avformat_open_input(&ac, path, 0, 0);
	
	if (re != 0){//開啟檔案失敗
		char buf[1024] = { 0 };
		av_strerror(re, buf, sizeof(buf));
		printf("file %s open failed because of : %s", path, buf);
		getchar();
		return -1;
	}
	
	int totalSec = ac->duration / AV_TIME_BASE;
	printf("指定的視訊檔案有 %d分%d秒\n", totalSec / 60, totalSec % 60);

	int videoStream = 0;
	AVCodecContext *videoCtx = NULL;
	for (int i = 0; i < ac->nb_streams; i++)
	{
		AVCodecContext *enc = ac->streams[i]->codec;
		
		if (enc->codec_type == AVMEDIA_TYPE_VIDEO){
			videoStream = i;
			videoCtx = enc;
			AVCodec *codec = avcodec_find_decoder(enc->codec_id);
			if (!codec){
				printf("無法解碼此視訊檔案\n");
				return -1;
			}
			int err = avcodec_open2(enc, codec, NULL);
			if (err != 0){
				char buf[1024] = { 0 };
				av_strerror(err, buf, sizeof(buf));
				printf(buf);
				return -2;
			}
			printf("\n");
			printf("成功開啟視訊編碼流\n");
		}
	}
	AVFrame *yuv = av_frame_alloc();
	for (;;){
		AVPacket pkt;
		re = av_read_frame(ac, &pkt);
		if (re != 0){
			break;
		}
		if (pkt.stream_index != videoStream)
		{
			av_packet_unref(&pkt);
			continue;
		}
		int pts = pkt.pts * r2d(ac->streams[pkt.stream_index]->time_base) * 1000;//得到幀的毫秒值

		//=============================================================================
		int got_picture = 0;
		int re = avcodec_decode_video2(videoCtx,yuv,&got_picture,&pkt);
		if (got_picture){
			printf("[%d]___", re);
		}
		//=============================================================================

		printf("pts = %d 毫秒\n", pts);
		av_packet_unref(&pkt);
	}
	

	avformat_close_input(&ac);

	QApplication a(argc, argv);
	MyPlayer w;
	w.show();
	return a.exec();
}


執行結果:



第二種方式:

#include "myplayer.h"
#include <QtWidgets/QApplication>
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
extern "C"{
#include <libavformat/avformat.h>
}
static double r2d(AVRational r){
	return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}
int main(int argc, char *argv[])
{
	av_register_all();
	char *path = "test.mp4";
	AVFormatContext *ac = NULL;
	int re = avformat_open_input(&ac, path, 0, 0);
	
	if (re != 0){//開啟檔案失敗
		char buf[1024] = { 0 };
		av_strerror(re, buf, sizeof(buf));
		printf("file %s open failed because of : %s", path, buf);
		getchar();
		return -1;
	}
	
	int totalSec = ac->duration / AV_TIME_BASE;
	printf("指定的視訊檔案有 %d分%d秒\n", totalSec / 60, totalSec % 60);

	int videoStream = 0;
	AVCodecContext *videoCtx = NULL;
	for (int i = 0; i < ac->nb_streams; i++)
	{
		AVCodecContext *enc = ac->streams[i]->codec;
		
		if (enc->codec_type == AVMEDIA_TYPE_VIDEO){
			videoStream = i;
			videoCtx = enc;
			AVCodec *codec = avcodec_find_decoder(enc->codec_id);
			if (!codec){
				printf("無法解碼此視訊檔案\n");
				return -1;
			}
			int err = avcodec_open2(enc, codec, NULL);
			if (err != 0){
				char buf[1024] = { 0 };
				av_strerror(err, buf, sizeof(buf));
				printf(buf);
				return -2;
			}
			printf("\n");
			printf("成功開啟視訊編碼流\n");
		}
	}
	AVFrame *yuv = av_frame_alloc();
	for (;;){
		AVPacket pkt;
		re = av_read_frame(ac, &pkt);
		if (re != 0){
			break;
		}
		if (pkt.stream_index != videoStream)
		{
			av_packet_unref(&pkt);
			continue;
		}
		int pts = pkt.pts * r2d(ac->streams[pkt.stream_index]->time_base) * 1000;//得到幀的毫秒值

		//=============================================================================
		int re = avcodec_send_packet(videoCtx,&pkt);
		if (re != 0){
			av_packet_unref(&pkt);
			continue;
		}
		re = avcodec_receive_frame(videoCtx,yuv);
		if (re != 0){
			av_packet_unref(&pkt);
			continue;
		}
		printf("[D]___");
		//=============================================================================

		printf("pts = %d 毫秒\n", pts);
		av_packet_unref(&pkt);
	}
	

	avformat_close_input(&ac);

	QApplication a(argc, argv);
	MyPlayer w;
	w.show();
	return a.exec();
}

執行結果:


相關推薦

ffmpeg系列視訊解碼方式

方式一: #include "myplayer.h" #include <QtWidgets/QApplication> #pragma comment(lib,"avformat.lib") #pragma comment(lib,"avutil.lib")

Shiro源代碼分析Session的方式

amp msg cto 開源 request cannot pad turn ssa 1、Shiro默認的Session處理方式 <!-- 定義 Shiro 主要業務對象 --> <bean id="s

javacpp-FFmpeg系列2:通用拉流解碼器,支持視頻拉流解碼並轉換為YUV、BGR24或RGB24等圖像像素數據

tope sca 封裝 ams 定義 throw tco 如何使用 都是 javacpp-ffmpeg系列: javacpp-FFmpeg系列之1:視頻拉流解碼成YUVJ420P,並保存為jpg圖片 javacpp-FFmpeg系列之2:通用拉流解碼器,支持視頻拉流解碼並

Nginx入門handler函式的掛載方式

請在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。 接著上次的文章,今天研究《深入理解Nginx模組開發與架構解析》一書中給出的mytest的例子,發現和 /tengine.taobao.org/book/ 一書中的例子不甚相同,尤其是在handler函式的掛在方

mybatis學習路----#{}, ${}傳引數方式的區別--附原始碼解讀

點滴記載,點滴進步,願自己更上一層樓。 首先下個結論, ${} 會將傳入的引數完全拼接到sql語句中,也就是相當於一個拼接符號。 也就是,最後的處理方式就相當於  String sql = select * from user where id=${value}....

SpringBoot學習筆記一【Idea下建立springboot示例、啟動原理分析與部署啟動方式

1、使用背景 首先說下我們為什麼使用springboot,原因有以下幾點 1、快速建立獨立執行的spring專案以及與主流框架繼承 2、使用嵌入式的Servlet容器,無需打成war包 3、starters自動依賴於版本控制 4、大量的自動配置,簡化開發,也可修改預設值 5、

總結Web使用者登入方式及JS資訊驗證操作——表單提交、ajax提交

登入大體有兩種方法一個是表單提交另一個就是ajax提交 1.表單提交 表單提交如果前端JS沒有驗證十分簡單,不詳述。 JS驗證使用者名稱、密碼是否為空 其中非submit和button按鈕 submit有一些注意事項 form中要onsubmit=“ret

Servlet系列第二建立方式(二)繼承GenericServlet類

package servlet; import javax.servlet.*; import java.io.IOException; import java.util.Enumeration;

Jmeter 跨線程組傳遞參數 方法

可能 spa 添加 all post edi 變量 sign 一個 終於搞定了Jmeter跨線程組之間傳遞參數,這樣就不用每次發送請求B之前,都需要同時發送一下登錄接口(因為同一個線程組下的請求是同時發送的),只需要發送一次登錄請求,請求B直接用登錄請求的參數即可,直到登

圖的遍歷方式

繼續 div input traversal 遍歷 n) logs i++ memset 圖的遍歷有兩種:深度優先和廣度優先。本文中,深度優先使用遞歸實現,每次遞歸找到第一個與當前結點相連且未輸出過的結點繼續往下遞歸,直至所有結點都已輸出。廣度優先將開始結點的所有鄰接結點全

Android學習筆記(36):Android的事件處理方式

post gravity cal log 基於 處理方法 hang mil 重寫 Android提供了兩種事件處理的方式:基於回調的事件處理 和 基於監聽的事件處理。 我們來說的easy理解一點: (1)基於回調的事件處理就是繼承GUI組件,並重寫該組件的

華為telnet的連接方式

telnet要求R2能遠程登陸上R1(使用password)方式第一種方式:[R1][R1]int e0/0/0[R1-Ethernet0/0/0]ip address 12.1.1.1 24[R1]user-interface vty 0 4[R1-ui-vty0-4]authentication-mode

html5中的Web Storage包括了存儲方式:sessionStorage和localStorage。

htm local 本地 存儲方式 刪除數據 tor web 兩種 session html5中的Web Storage包括了兩種存儲方式:sessionStorage和localStorage。 sessionStorage用於本地存儲一個會話(session)中的數據,

Kaldi語料的切分/組織方式及其處理

out pad ati bottle pri 特征提取 文件的 code val text中每一個文本段由一個音頻索引(indexed by utterance) 使用該方式的egs:librispeech、timit、thchs30、atc_en、atc_cn 語料

Tiled Editor 圖塊的導入方式

點擊 編輯 edi 面板 src 選擇 .cn 測試 工程 一、圖塊集圖塊的導入。   打開或者創建地圖後,新建 新圖塊。    彈出新圖塊面板      圖塊類型選擇 “基於圖塊集圖塊”,一定要選擇“嵌入地圖”,否則需要另存為其他類型的文件,生成遊戲工程無法解析的

javascript基礎函數的定義方法

函數 div code add 基礎 clas col ava bsp 第一種方式:可以在函數定義之前調用也可以在函數定義之後調用: (0)函數的調用 add(1,2) //可以調用 (1)函數的定義: function add(x,y) { con

第63天:json的聲明方式

添加 shift ddr rom ole 們的 刪除 按鈕 pop 一、 json 兩種聲明方式 1、 對象聲明 var json = {width:100,height:100} 2、 數組聲明 var man = [ // 數組的 js

Cassandra登錄方式cassandra-cli / csqlsh

cassandra兩種登錄方式cassandra-cli / csqlsh(1)cassandra-clicassadnra-cli命令在cassandra2.2中被拋棄,以後登錄訪問cassandra可以使用cqlsh[tnuser@sht-sgmhadoopdn-02 cassandra]$ cassan

Arduino通信篇系列print()和write()輸出方式的差異

scl 監視 () nbsp 函數 1.2 系列 輸出數據 int 我們都知道,在HardwareSerial類中有print()和write()兩種輸出方式, 兩個都可以輸出數據,但其輸出方式並不相同。 例子: float FLOAT=1.23456; int INT=1

jmeter常用額錄制方式

就是 圖片 body 方式 技術 mage 錄制 image jmeter代理 1、Badboy錄制 默認打開就是錄制狀態, 2、jmeter代理錄制 錄制東西太多 jmeter常用額兩種錄制方式