1. 程式人生 > >使用ffmpeg解碼音訊檔案到PCM格式

使用ffmpeg解碼音訊檔案到PCM格式

最近忙於使用ffmpeg播放音樂檔案的專案,現將開發經驗總結如下:

一、解碼音樂檔案的大致流程如下:

1,開啟音樂檔案,呼叫av_open_input_file()

2,查詢audio stream,呼叫av_find_stream_info()

3,查詢對應的decoder,呼叫avcodec_find_decoder()

4,開啟decoder,呼叫avcodec_open()

5,讀取一楨資料包,呼叫av_read_frame()

6,解碼資料包,呼叫avcodec_decode_audio3()

7,將解碼後的資料返回

這樣,得到解碼後的PCM資料之後,我們可以播放、也可以encode成其他格式。

二、相關程式碼:

1,開啟檔案

// return 0: OK
// return -1: arguments are wrong
int internal_open(const char* file)
{
	int i = 0;
	int res = 0;
	LOGD("enter internal_open(), file name:%s", file);

	if (file == 0 || strlen(file) == 0)
	{
		LOGE("%s, argument file is wrong!", __FUNCTION__);
		return -1;
	}

	// try open file
	if ((res = av_open_input_file(&m_format_ctx, file, NULL, 0, NULL)) != 0)
	{
		LOGE("%s, av_open_input_file() return failed!", __FUNCTION__);
		return res;
	}

	// find streams information
	if ((res = av_find_stream_info(m_format_ctx) < 0))
	{
		LOGE("%s, av_find_stream_info() could not find codec parameters!", __FUNCTION__);
		return res;
	}

	av_dump_format(m_format_ctx, 0, file, 0);

	for(i = 0; i < m_format_ctx->nb_streams; i++)
	{
		// get audio stream id
		if(m_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			m_audio_stream = i;
			break;
		}
	}
	if(m_audio_stream == -1)
    	{
		LOGE("%s, find audioStream failed!", __FUNCTION__);
		return -4;
    	}

	// get audio stream codec
	m_codec_ctx = m_format_ctx->streams[m_audio_stream]->codec;

	// find the mpeg audio decoder
	m_codec = avcodec_find_decoder(m_codec_ctx->codec_id);
	if (!m_codec)
	{
		LOGE("%s, codec not found!", __FUNCTION__);
		return -5;
	}

	// open it
	if (avcodec_open(m_codec_ctx, m_codec) < 0)
	{
		LOGE("%s, could not open codec!", __FUNCTION__);
		return -7;
	}

	LOGD("exit internal_open()");
	return 0;
}

2,解碼資料

int internal_getaudio(unsigned char buff[], long num_samples)
{
	//AVPacket avpkt;
	long copied_len = 0;
	int frame_size = 0;
	int decoded_len = 0;
	int real_copied = 0;
	int decoded_audio_len = 0;
	unsigned char* valid_data_pointer = 0;

	LOGD("enter internal_getaudio()");

	// copy the backup (has not copied in last time) data at first!
	if (m_audio_buff_backup_len > 0)
	{
		LOGI("%s, has last not copied data in backup buff, length:%d", __FUNCTION__, m_audio_buff_backup_len);
		if (m_audio_buff_backup_len >= num_samples)
		{
			memcpy(buff, m_audio_buff_backup, num_samples);
			copied_len += num_samples;
			LOGI("%s, only copy data from backup buff, return 0", __FUNCTION__);
		}
		else
		{
			memcpy(buff, m_audio_buff_backup, m_audio_buff_backup_len);
			copied_len += m_audio_buff_backup_len;
			LOGI("%s, copy %d length data from backup buff", __FUNCTION__, m_audio_buff_backup_len);
		}
	}

	// decode new data
	while (copied_len < num_samples && av_read_frame(m_format_ctx, &m_avpkt) >= 0)
	{
		LOGI("%s, av_read_frame() return successful!", __FUNCTION__);
		if (m_avpkt.stream_index == m_audio_stream)
		{
			while (m_avpkt.size > 0)
			{
				LOGI("%s, current packet size:%d", __FUNCTION__, m_avpkt.size);
				frame_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
				memset(m_audio_buff, 0, AVCODEC_MAX_AUDIO_FRAME_SIZE);
				decoded_len = avcodec_decode_audio3(m_codec_ctx, (short *)m_audio_buff, &frame_size, &m_avpkt);
				LOGI("%s, current decoded size:%d", __FUNCTION__, decoded_len);
				if (decoded_len > 0)
				{
					m_avpkt.size -= decoded_len;
					m_avpkt.data += decoded_len;

					// copy audio data to output buff
					if ((num_samples-copied_len) > decoded_audio_len)
					{
						memcpy(buff+copied_len, m_audio_buff, frame_size);
						copied_len += frame_size;
						LOGI("%s, copy1, %d bytes has copied to output buff, total:%d!", __FUNCTION__, frame_size, copied_len);
					}
					else
					{
						real_copied = (num_samples-copied_len);
						memcpy(buff+copied_len, m_audio_buff, real_copied);
						copied_len += real_copied;
						LOGI("%s, copy2, %d bytes has copied to output buff, total:%d!", __FUNCTION__, real_copied, copied_len);

						m_audio_buff_backup_len = frame_size - real_copied;
						memcpy(m_audio_buff_backup, m_audio_buff+real_copied, m_audio_buff_backup_len);
						LOGI("%s, copy2, %d bytes has copied to backup buff!", __FUNCTION__, m_audio_buff_backup_len);
						break;
					}
				}
				else
				{
					LOGE("%s, decoded size is error, returned!", __FUNCTION__);
					break;
				}
			}
		}
	}

	LOGD("exit internal_getaudio(), decoded length: %d", copied_len);
	return copied_len;
}

3,關閉和釋放資源

int internal_close()
{
	if (m_format_ctx)
	{
		av_close_input_file(m_format_ctx);
		m_format_ctx = 0;
	}

	return 0;
}
int internal_release()
{
	if (m_avpkt.data)
	{
		av_free_packet(&m_avpkt);
	}
	if (!m_codec_ctx)
	{
		avcodec_close(m_codec_ctx);
		m_codec_ctx = 0;
	}

	return 0;
}

相關推薦

使用ffmpeg解碼音訊檔案PCM格式

最近忙於使用ffmpeg播放音樂檔案的專案,現將開發經驗總結如下: 一、解碼音樂檔案的大致流程如下: 1,開啟音樂檔案,呼叫av_open_input_file() 2,查詢audio stream,呼叫av_find_stream_info() 3,查詢對應的decode

使用FFMpeg 解碼音訊檔案

本篇文章將介紹使用FFMpeg解碼音訊檔案為PCM的資料。 使用FFMpeg獲取想要的音訊資料的步驟如下: 解封裝(MP3檔案)->解碼(MP3編碼)->PCM資料重取樣 1. 解封裝 使用FFMpeg解封裝的步驟如下: 使用函式 av_re

java音訊檔案pcm轉wav

import java.io.FileInputStream; import java.io.FileOutputStream; /**  * PCM檔案轉換成Wav格式音訊  * @author chuanye.wan  *  */ public cla

speech_recognition實現錄音ffmpeg實現音訊檔案轉換,並用百度語音的sdk實現語音識別

專案說明: 在windows平臺下,使用speech_recognition記錄音訊,並轉換為16k的wav, 之後利用ffmpeg將wav轉化為pcm檔案,上傳到百度語音端,返回語音資訊,並利用pyttsx3添加了簡單的互動功能。 需求模組: speech_recognit

FFmpeg解碼MP4檔案為h264和YUV檔案

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

FFMPEG解碼mp3到pcm

int Mp3Decoder::prepare() { int ret=0; //1 開啟檔案獲取fmt_ctx(用於解封裝) if(avformat_open_input(&fmt_ctx,src_filename,NULL,NULL)<0){

JAVA 獲取音訊檔案(ogg格式)毫秒時長

最近在寫zip包加密解密,需要計算zip包中ogg格式音訊檔案的毫秒時長,網上翻了半天硬是沒找到,然後找到了個突破口(jaudiotagger) 匯入一下類庫 <dependency>       <groupI

ffmpeg解碼視訊檔案並播放

        最近學習了一下如何使用ffmpeg解碼音視訊,網上的教程挺多但是也挺雜的,搞了好幾天,明白了ffmpeg解碼音視訊的大體流程,這裡記錄一下ffmpeg解碼視訊並播放音視訊的例子,但並沒有做音訊、視訊播放 的同步處理。 直接上程式碼: #include &l

使用ffmpeg 操作音訊檔案前後部分靜音移除.

  指令特別簡單, 但是卻琢磨了一下午. 總結看文件時要細心, 主要ffmpeg的版本要 8.2.1 以上 ffmpeg -i in.mp3 -af silenceremove=start_periods=1:start_threshold=-30dB:stop_periods=0:sto

FFMPEG 解碼音訊

目的 通過FFMPEG解碼音訊的碼流,得到PCM的音訊取樣資料並用AudioTraker播放 步驟 1.註冊所有元件 av_register_all(); 2.拿到封裝格式上下文 AVFormatContext *avFormatContext =

ffmpeg解碼h264檔案,opencv顯示

H264.h #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> #include <winsock2

FFMPEG學習筆記---SDL+FFmpeg解碼音訊資料

音訊解析流程基本跟視訊差不太多,都是藉助FFMpeg開啟檔案,獲取檔案相關資訊,找到音視訊流,開啟解碼器,進行資料讀取,其中有時會用到轉換函式,將圖片格式或者音訊格式轉換為我們想要的或者裝置可以識別的格式,然後進行讀取播放即可;下面是程式碼:#include <stdi

java呼叫FFmpeg解碼本地檔案 使用Javacv

package com.aast.test; import java.io.*; import java.nio.ByteBuffer; import org.bytedeco.javacpp.*; import org.bytedeco.javacpp.annotati

ffmpeg解碼音訊的兩種方式(二)根據同步位元組解析音訊

根據adts同步頭提取aac音訊單幀: #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <string.h> extern "C" { #includ

用DAC解碼PCM資料播放WAV格式音訊檔案

WAV音訊用的是PCM協議,大致就是前面44位元組的一堆描述,用於辨別檔案型別、大小,後面一堆音訊資料。 關於WAV格式、RIFF格式、PCM協議這些的關係,在這篇文章描述得很詳細,這裡就不做介紹了。 RIFF和WAVE音訊檔案格式 先看程式碼: void readWave()

4.基於FFMPEG音訊解碼PCM

繼續FFMPEG學習之路,前面瞭解了將PCM編碼為AAC檔案,接下來則需要了解一下解碼方面,將MP3/AAC等音訊格式解碼為PCM資料,記錄一下過程。。。 1)解碼流程 整個解碼流程採用虛擬碼大致如下: 初始化複用器和解複用器—>獲取輸入檔案的一些資訊—->查詢解碼器

用ADC編碼PCM資料錄製WAV格式音訊檔案

因為PCM檔案直接儲存取樣的量化值,所以按照規定格式,先編寫頭,再寫音訊資料就可以了。 這裡是錄製一個6s長度的WAV音訊檔案,PCM格式,單聲道,44.1kHz取樣頻率,88200的音訊位元速率,16bit的資料,算下來的資料大小是88200*6=529.200KB。 //(資料欄

關於ffmpeg 的總結(一個linux 下 集 螢幕錄影錄音,音訊視訊轉換,合併音訊視訊檔案格式轉換於一身的命令)

當然先安裝了 gentoo 下一條命令搞定 emerge  ffmpeg  格式轉換 (將file.avi 轉換成output.flv)      ffmpeg -i  file.avi   output.flv        -i 表示輸入檔案

PCM音訊檔案格式的頭資訊

一個裸的PCM格式音訊資料,如果不帶頭資訊,不知道其取樣率等相關資訊,就無法用播放器播放出來。下面是預設的頭資訊格式: //音訊頭部格式 struct wave_pcm_hdr { char

FFmpeg把MP4檔案解碼為YUV,然後通過SDL播放

#include <iostream> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swsca