ffmpeg音頻php源碼成品,ffmpeg音視頻高級開發實戰

本文目錄一覽:

怎樣使用ffmpeg 進行音頻解碼

安裝完成ffmpeg後,就可以使用ffmpeg進行音頻文件格式轉換。比如 ./ffmpeg -i /media/1.mp3 /media/1.wav, 通過該命令行可以將/media文件夾下1.mp3文件轉換成WAV格式的。

但是反過來 ./ffmpeg -i /media/1.WAV /media/1.MP3 卻不能轉換成Mp3格式,提示如下錯誤(找不到編碼器):

Stream mapping:

Stream #0:0 – #0:0 (wav – ?)

Encoder (codec none) not found for output stream #0:0

如果強行指定編碼器 ./ffmpeg -i /media/1.wav -acodec mp3 /media/1.mp3, 仍提示找不到編碼器錯誤:

Unknown encoder ‘mp3’

這是因為,ffmpeg雖然是個開源軟件,但因為具體格式的版權原因,它並沒有包含所有的編解碼格式,或者有個格式只有對應的解碼器,但沒有編碼器,比如 Mp3就只有解碼器,能播放Mp3文件,但卻沒有Mp3的編碼器,無法將其它格式轉換成Mp3。可以通過命令行 ./ffmpeg -codecs 查詢編解碼配置,第一個D表示Decoder,該格式能夠解碼;E表示Encoder,該格式可以編碼。從中可以看出Mp3不能編碼,Mp2倒是即可解碼 也可編碼。如何解決這個問題呢?

D A D mp1 MP1 (MPEG audio layer 1)

D A D mp1float MP1 (MPEG audio layer 1)

DEA D mp2 MP2 (MPEG audio layer 2)

D A D mp2float MP2 (MPEG audio layer 2)

D A D mp3 MP3 (MPEG audio layer 3)

D A D mp3adu ADU (Application Data Unit) MP3 (MPEG audio layer 3)

D A D mp3adufloat ADU (Application Data Unit) MP3 (MPEG audio layer 3)

我的第一個方法是自己寫代碼來完成。源碼文件中,Allcodecs.c中對各個格式進行註冊,先修改Mp3的註冊行,改為同時註冊解碼器和編碼器:

REGISTER_ENCDEC (MP2, mp2);

REGISTER_DECODER (MP2FLOAT, mp2float);

REGISTER_DECODER (MP3, mp3) // 此行修改為 REGISTER_ENCDEC (MP3, mp3)

然後新增Mp3編碼器的實現Struct,裏面Init函數、encode函數、close函數使用Mp2的函數,因為我也不知道如何去實現Mp3的函數,或者說到代碼實現級我也不知道Mp3和Mp2的區別在哪。

AVCodec ff_mp3_encoder = {

.name = “mp3”,

.type = AVMEDIA_TYPE_AUDIO,

.id = CODEC_ID_MP3,

.priv_data_size = sizeof(MpegAudioContext),

.init = MPA_encode_init,

.encode = MPA_encode_frame,

.close = MPA_encode_close,

.sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE},

.supported_samplerates= (const int[]){44100, 48000, 32000, 22050, 24000, 16000, 0},

.long_name = NULL_IF_CONFIG_SMALL(“MP3 (MPEG audio layer 3)”),

.defaults = mp3_defaults,

};

重新編譯上線。 用命令行./ffmpeg -i /media/1.WAV /media/1.MP3 試了一下,能成功生成1.mp3文件,文件也能播放。似乎沒有問題了,單用 file /media/1.mp3 查看了一下,發現文件不是Mp3格式的,而是Mp2格式的:

/media/1.mp3: MPEG ADTS, layer II, v1, 128 kbps, 44.1 kHz, Stereo

很遺憾,自行修改代碼的方式行不通,因為不是每個編解碼格式協議的專家,自行修改代碼失敗的風險很大,不僅是Mp3,還有一些其他格式比如AMR OGG H.263是沒有編碼器的。所以,第二個方案,使用成熟的第三方編碼器和ffmpeg結合。

Mp3比較好的開源第三方庫是libmp3lame(簡稱Lame)。我下了一個最新版本(3.99.4)的Lame源碼,編譯它:

首先配置: ./configure –prefix=/shared –enable-shared –enable-static

然後編譯: make

make install

生成文件: 動態鏈接庫 /shared/lib/libmp3lame.so 和 靜態鏈接庫 /shared/lib/libmp3lame.a。這裡只需要使用動態鏈接庫,將.so文件拷貝到/lib中,這個文件夾是動態鏈接庫的默認搜索路徑, 讓ffmpeg運行時可以找到。

然後對ffmpeg配置libmp3lame: ./configure –enable-libmp3lame

重新編譯ffmpeg,運行轉化命令,看看效果如何。

首先執行 ./ffmpeg -codecs 查看可用編解碼的變化,可以看到多出了libmp3lame編碼器,帶E的:

D V D lagarith Lagarith lossless

EA libmp3lame libmp3lame MP3 (MPEG audio layer 3)

EV ljpeg Lossless JPEG

D V D loco LOCO

然後執行 ./ffmpeg -i /media/1.WAV /media/1.MP3, 生成1.mp3,用File命令查看,確實是Mp3文件。

/media/1.mp3: Audio file with ID3 version 2.4.0, contains: MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo

大功告成,問題解決。

也可在命令行中指定編解碼生成Mp3文件:./ffmpeg -i /media/1.WAV -acodec libmp3lame /media/1.MP3.

windows下編譯ffmpeg源碼及常見問題

由於公司項目中會用到ffmpeg,而且會用到h265轉碼h264的功能,想要學習ffmpeg,先從編譯開始吧。我編譯的過程主要是從以下博客中學習的,此文主要是記錄中間遇到的問題及解決方法。

CC=cl ./configure –enable-shared

這個可能是因為 pdk-config 的 PKG-CONFIG-PATH 配置問題,我是在etc/profile文件里找到PKG-CONFIG-PATH的配置路徑(我的是/usr/lib/pkgconfig),然後將pkgconfig裏面的三個 .pc文件複製到/usr/lib/pkgconfig文件夾里即可

因為博客中只提到將編譯好的x265文件夾中的lib目錄複製過去,其實include文件夾也要複製過去,我把bin、include和lib都複製到usr/local對應的目錄中

不要將msys64裝在帶空格的文件夾中,否則編譯失敗,也不要將原先裝好的文件夾整個複製到另一個沒有空格的文件夾中,這樣編譯也會報錯。

求ffmpeg音頻壓縮代碼(wav壓縮成wma)

這個簡單。大致的思路是

1.打開wav文件

2.打開要輸出的wma文件

3.不停的讀取數據幀

4.讀取以後解碼並寫入wma

5.關閉wav文件

6.關閉wma文件

重新寫例子太麻煩貼點代碼吧

#include “Debug.h”

#include “FFMpegAVFileReader.h”

#include “FFMpegAVFileReaderFactory.h”

#include sstream

#include “yk_convert.h”

static char h264_head[4] = {(char)0x00,(char)0x00,(char)0x00,(char)0x01};

namespace YK

{

FFMpegAVFileReader::FFMpegAVFileReader()

{

ffmpeg_avcodec_init();

ffmpeg_av_register_all();

av_log_set_callback(ffmpeg_log_callback);

m_format_context = 0;

m_input_format = 0;

m_format_parameters = 0;

m_packet = (AVPacket*)av_mallocz(sizeof(AVPacket));

}

FFMpegAVFileReader::~FFMpegAVFileReader()

{

Close();

av_free(m_packet);

}

avfile_reader_param_t* FFMpegAVFileReader::GetParam()

{

//YK::AutoLock l(m_lock);

return m_param;

}

void FFMpegAVFileReader::Seek(int pts)

{

YK::AutoLock l(m_lock);

int ret = av_seek_frame(m_format_context,-1,(YK::int64_t)pts * (YK::int64_t)1000,AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY);

//if(ret = 0)

//{

// for(int i = 0; i m_format_context-nb_streams; i++)

// {

// avcodec_flush_buffers( m_format_context-streams[i]-codec );

// }

//}

//std::stringstream ss;

//ss “pts = ” pts

// ” ret = ” ret std::endl;

//OutputDebugString(ss.str().data());

}

void FFMpegAVFileReader::GetDuration(double start,double end)

{

//YK::AutoLock l(m_lock);

start = (double)(m_start_time / 1000000);

end = start + (double)(m_duration / 1000000);

}

service_error_t FFMpegAVFileReader::Open(int time_out)

{

YK::AutoLock l(m_lock);

service_error_t service_error;

// 打開文件

if (av_open_input_file(m_format_context,TToANSI(m_param.input_file_path).data(),m_input_format,0,m_format_parameters) 0)

{

service_error.init(service_error_type_failed,”av_open_input_file failed”);

return service_error;

}

// 查詢流信息

if(av_find_stream_info(m_format_context) 0)

{

service_error.init(service_error_type_failed,”av_find_stream_info failed”);

return service_error;

}

m_start_time = m_format_context-start_time;

m_duration = m_format_context-duration;

#ifdef _DEBUG

pFile = fopen(“D:/1.out”,”w+b”);

#endif

// 保存流信息

av_stream_info_t av_stream_info;

for(unsigned int i = 0; i m_format_context-nb_streams; i++)

{

AVStream *st = m_format_context-streams[i];

AVCodecContext *enc = st-codec;

if(enc-codec_type == AVMEDIA_TYPE_AUDIO)

{

// 音頻

av_stream_info.av_stream_info_type = av_stream_info_type_audio;

av_stream_info.codec_id = codec_id_none;

//channel_layout = enc-channel_layout;

av_stream_info.audio_channels = enc-channels;

av_stream_info.audio_samplepersec = enc-sample_rate;

av_stream_info.audio_bitpersample = yk_sample_format(enc-sample_fmt);

//audio_sample_fmt = enc-sample_fmt;

//input_codecs[nb_icodecs++] = avcodec_find_decoder_by_name(audio_codec_name);

av_stream_info.codec_id = yk_code_id(enc-codec_id);

av_stream_info.extradata_size = enc-extradata_size;

if(av_stream_info.extradata_size)

memcpy(av_stream_info.extradata,enc-extradata,enc-extradata_size);

if(av_stream_info.codec_id == codec_id_mp3)

{

av_stream_info.extradata_size = sizeof(mpeg1_waveformat_extradata);

mpeg1_waveformat_extradata* pMpeg1WaveFormat = (mpeg1_waveformat_extradata*)av_stream_info.extradata;

pMpeg1WaveFormat-dwHeadBitrate = enc-bit_rate;

pMpeg1WaveFormat-dwPTSHigh = 0;

pMpeg1WaveFormat-dwPTSLow = 0;

pMpeg1WaveFormat-fwHeadFlags = 25;

pMpeg1WaveFormat-fwHeadLayer = ACM_MPEG_LAYER3;

pMpeg1WaveFormat-fwHeadMode = ACM_MPEG_STEREO;

pMpeg1WaveFormat-fwHeadModeExt = 1;

pMpeg1WaveFormat-wHeadEmphasis = 1;

}

AddStreamInfo(av_stream_info);

m_stream_audio_index = i;

}

else if(enc-codec_type == AVMEDIA_TYPE_VIDEO)

{

// 視頻

av_stream_info.av_stream_info_type = av_stream_info_type_video;

av_stream_info.codec_id = codec_id_none;

av_stream_info.video_width = enc-width;

av_stream_info.video_height = enc-height;

av_stream_info.video_profile = enc-profile;

av_stream_info.video_level = enc-level;

if(av_stream_info.video_profile 0)

{

av_stream_info.video_profile = 77;

}

if(av_stream_info.video_level 0)

{

av_stream_info.video_level = 30;

}

av_stream_info.extradata_size =

iOS利用FFmpeg解碼音頻數據並播放

利用FFmepg解析並解碼音頻流數據,然後將解碼後的音頻數據送給Audio Queue以實現播放.

利用FFmpeg解析音頻數據流, 利用FFmpeg解碼音頻數據為PCM格式. 利用Audio Queue Player實現音頻數據播放.

本例以一個蘋果原生相機錄製的.MOV文件為例, 將該文件使用FFmpeg解析並解碼,將解碼後的數據放入傳輸隊列中,然後開啟audio queue player, 播放器在回調函數中輪循取出隊列中的數據實現播放.

FFmpeg parse流程

FFmpeg解碼流程

為了每次能夠重新播放,這裡需要標記當前是否為解碼的第一幀數據,以重新啟動播放器. 另一點是使用NSTimer等待音頻數據放入隊列再開始播放,因為audio queue是驅動播放模式,所以必須等音頻數據放入傳輸隊列再開始播放.

從Parse模塊中可以獲取當前文件對應FFmepg的上下文對象 AVFormatContext .因此音頻流解碼器信息可以直接獲取.

AVFrame 作為解碼後原始的音視頻數據的容器.AVFrame通常被分配一次然後多次重複(例如,單個AVFrame以保持從解碼器接收的幀)。在這種情況下,av_frame_unref()將釋放框架所持有的任何引用,並在再次重用之前將其重置為其原始的清理狀態。

調用avcodec_send_packet將壓縮數據發送給解碼器.最後利用循環接收avcodec_receive_frame解碼後的音視頻數據.

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/196011.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-03 09:51
下一篇 2024-12-03 09:52

相關推薦

  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • 雲智直聘 源碼分析

    本文將會對雲智直聘的源碼進行分析,包括前端頁面和後端代碼,幫助讀者了解其架構、技術實現以及對一些常見的問題進行解決。通過本文的閱讀,讀者將會了解到雲智直聘的特點、優勢以及不足之處,…

    編程 2025-04-29
  • Django框架:從簡介到項目實戰

    本文將從Django的介紹,以及如何搭建Django環境開始,逐步深入到Django模型、視圖、模板、表單,最後通過一個小型項目實戰,進行綜合性的應用,讓讀者獲得更深入的學習。 一…

    編程 2025-04-28
  • 鍵值存儲(kvs):從基礎概念到實戰應用

    本文將從基礎概念入手,介紹鍵值存儲(kvs)的概念、原理以及實戰應用,並給出代碼實現。通過閱讀本文,您將了解鍵值存儲的優缺點,如何選擇最適合的鍵值存儲方案,以及如何使用鍵值存儲解決…

    編程 2025-04-28
  • Python網站源碼解析

    本文將從多個方面對Python網站源碼進行詳細解析,包括搭建網站、數據處理、安全性等內容。 一、搭建網站 Python是一種高級編程語言,適用於多種領域。它也可以用於搭建網站。最常…

    編程 2025-04-28
  • Python編程實戰:用Python做網頁與HTML

    Python語言是一種被廣泛應用的高級編程語言,也是一種非常適合於開發網頁和處理HTML的語言。在本文中,我們將從多個方面介紹如何用Python來編寫網頁和處理HTML。 一、Py…

    編程 2025-04-28
  • 源碼是什麼

    源碼是一段計算機程序的原始代碼,它是程序員所編寫的可讀性高、理解性強的文本。在計算機中,源碼是指編寫的程序代碼,這些代碼按照一定規則排列,被計算機識別並執行。 一、源碼的組成 源碼…

    編程 2025-04-27
  • Webrtc音視頻開發React+Flutter+Go實戰PDF

    本文將從多個方面介紹如何使用React、Flutter和Go來進行Webrtc音視頻開發,並提供相應的代碼示例。 一、Webrtc音視頻開發介紹 Webrtc是Google開發的一…

    編程 2025-04-27
  • Python自動化交易實戰教程

    本教程將詳細介紹使用Python進行自動化交易的方法,包括如何選擇優秀的交易策略、如何獲取市場數據、如何實現策略並進行回測,以及如何使用Python自動化下單,並進行實盤交易,讓您…

    編程 2025-04-27
  • Go源碼閱讀

    Go語言是Google推出的一門靜態類型、編譯型、並髮型、語法簡單的編程語言。它因具有簡潔高效,內置GC等優秀特性,被越來越多的開發者所鍾愛。在這篇文章中,我們將介紹如何從多個方面…

    編程 2025-04-27

發表回復

登錄後才能評論