国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android音視頻開發(fā)(三)——MediaExtractor和MediaMuxer的使用

這篇具有很好參考價值的文章主要介紹了Android音視頻開發(fā)(三)——MediaExtractor和MediaMuxer的使用。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

了解了音視頻的編解碼過程,我們接下來使用一下經(jīng)常跟MediaCodec一起搭配的MediaExtractor和MediaMuxer。最后會使用一個簡單的demo來了解具體了解這兩個工具類的使用過程。這一節(jié)我們就先不講MediaCodec了,放到下節(jié)的demo。

Android音視頻開發(fā)(三)——MediaExtractor和MediaMuxer的使用

一、MediaExtractor

Android提供了一個MediaExtractor類,可以用來分離容器中的視頻track音頻track。

主要API介紹:

  • setDataSource(String path):即可以設置本地文件又可以設置網(wǎng)絡文件
  • getTrackCount():得到源文件通道數(shù)?
  • getTrackFormat(int index):獲取指定(index)的通道格式
  • getSampleTime():返回當前的時間戳?
  • readSampleData(ByteBuffer byteBuf, int offset):把指定通道中的數(shù)據(jù)按偏移量讀取到ByteBuffer中;
  • advance():讀取下一幀數(shù)據(jù)
  • release(): 讀取結束后釋放資源

MediaExtractor 的使用主要有這么幾步:

  1. 設置數(shù)據(jù)源
  2. 獲取通道數(shù),切換到想要的軌道
  3. 循環(huán)讀取每幀的樣本數(shù)據(jù)
  4. 完成后釋放資源

二、MediaMuxer

MediaMuxer的作用是生成音頻或視頻文件;還可以把音頻與視頻混合成一個音視頻文件。

相關API介紹:

  • MediaMuxer(String path, int format):path:輸出文件的名稱 ?format:輸出文件的格式;當前只支持MP4格式;
  • addTrack(MediaFormat format):添加通道;我們更多的是使用MediaCodec.getOutpurForma()或Extractor.getTrackFormat(int index)來獲取MediaFormat;也可以自己創(chuàng)建;
  • start():開始合成文件
  • writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo):把ByteBuffer中的數(shù)據(jù)寫入到在構造器設置的文件中;
  • stop():停止合成文件
  • release():釋放資源

參數(shù)

int MUXER_OUTPUT_3GPP

3GPP媒體文件格式

int MUXER_OUTPUT_HEIF

HEIF媒體文件格式

int MUXER_OUTPUT_MPEG_4

MPEG4媒體文件格式

int MUXER_OUTPUT_OGG

Ogg媒體文件格式

int MUXER_OUTPUT_WEBM

WEBM媒體文件格式

MediaMuxer的使用步驟:

  1. 設置目標文件路徑和音視頻格式
  2. 添加要合成的軌道,包括音軌和視軌
  3. 開始合成,循環(huán)寫入每幀樣本數(shù)據(jù)
  4. 完成后釋放

三、MediaFormat

????????用MediaCodec來進行編解碼,在創(chuàng)建MediaCodec時需要調用configure方法進行配置,Mediaformat則是configure需要傳入的一個參數(shù)。

?3.1 視頻類型的Mediaformat

可以通過如下代碼創(chuàng)建視頻類型Mediaformat:

MediaFormat videoFormat = MediaFormat.createVideoFormat(videoType, width, height);

方法的參數(shù)類型:

  • videoType常用的有兩種:

????????MediaFormat.MIMETYPE_VIDEO_AVC(H.264
????????MediaFormat.MIMETYPE_VIDEO_HEVC(H.265

  • widthheight需要根據(jù)底層支持的分辨率來設置,如果width和height設置的不符合要求會出現(xiàn)如下錯誤:
E/CameraCaptureSession: Session 1: Failed to create capture session; configuration failed

對于視頻類型而言有下列四個配置是必須指定的:手動配置直接獲取原視頻的配置

// 指定編碼器顏色格式 
videoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
    MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);

// 指定幀率
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);

// 指定比特率
videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 10000000);

//指定關鍵幀時間間隔,一般設置為每秒關鍵幀
videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);

?3.2 音頻類型的Mediaformat

可以通過如下代碼創(chuàng)建音頻類型Mediaformat:

MediaFormat audioFormat = MediaFormat.createAudioFormat(audioType, sampleRate, channelCount);

方法的參數(shù)類型:

  • audioType:常用的是MediaFormat.MIMETYPE_AUDIO_AAC
  • sampleRate:采樣率
  • channelCount:聲道數(shù)量

單聲道 channelCount=1 , 雙聲道 channelCount=2

對于音頻類型而言有一個配置是必須指定的:

//音頻比特率(碼率)
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);

四、MediaCodec.BufferInfo?

????????用于描述解碼得到的byte[]數(shù)據(jù)的相關信息,每緩沖區(qū)元數(shù)據(jù)包括指定相關編解碼器(輸出)緩沖區(qū)中有效數(shù)據(jù)范圍的偏移量和大小。

主要有四個屬性:

  • int?flags :與緩沖區(qū)關聯(lián)的緩沖區(qū)標志
  • int?offset :緩沖區(qū)中數(shù)據(jù)的起始偏移量。
  • long?presentationTimeUs :緩沖區(qū)的顯示時間戳,以微秒計。這是從相應的輸入緩沖區(qū)傳入的表示時間戳中獲得的。對于大小為0的緩沖區(qū),應該忽略這一點。
  • int?size :緩沖區(qū)中的數(shù)據(jù)量(以字節(jié)為單位)。如果這是0緩沖區(qū)中沒有數(shù)據(jù),可以丟棄。大小為0的緩沖區(qū)的唯一用途是攜帶流結束標記。

flags詳解:

  • 與緩沖區(qū)關聯(lián)的緩沖區(qū)標志。...的結合MediaCodec.BUFFER_FLAG_KEY_FRAMEMediaCodec.BUFFER_FLAG_END_OF_STREAM.
  • 作為關鍵幀的編碼緩沖區(qū)標有MediaCodec.BUFFER_FLAG_KEY_FRAME.
  • 對應于輸入緩沖區(qū)的最后一個輸出緩沖區(qū)用MediaCodec.BUFFER_FLAG_END_OF_STREAM也將標有MediaCodec.BUFFER_FLAG_END_OF_STREAM。在某些情況下,這可能是一個空緩沖區(qū),其唯一目的是攜帶流結束標記。

值是0或以下各項的組合MediaCodec.BUFFER_FLAG_SYNC_FRAME,?MediaCodec.BUFFER_FLAG_KEY_FRAME,?MediaCodec.BUFFER_FLAG_CODEC_CONFIG,?MediaCodec.BUFFER_FLAG_END_OF_STREAM,?MediaCodec.BUFFER_FLAG_PARTIAL_FRAME、以及Android . media . media codec . buffer _ FLAG _ MUXER _ DATA

  • ?BUFFER_FLAG_CODEC_CONFIG?? 常數(shù)值:2:這表明如此標記的緩沖區(qū)包含編解碼器初始化/編解碼器特定數(shù)據(jù),而不是媒體數(shù)據(jù)。
  • BUFFER_FLAG_END_OF_STREAM 常數(shù)值:4:這表示流的結束,即在此之后將沒有緩沖器可用,當然,除非,flush()如下。
  • BUFFER_FLAG_KEY_FRAME 常數(shù)值:1:這表明如此標記的(編碼的)緩沖區(qū)包含關鍵幀的數(shù)據(jù)。
  • BUFFER_FLAG_PARTIAL_FRAME 常數(shù)值:8:這表示緩沖區(qū)只包含一幀的一部分,解碼器應該對數(shù)據(jù)進行批處理,直到在解碼該幀之前出現(xiàn)一個沒有該標志的緩沖區(qū)。
  • BUFFER_FLAG_SYNC_FRAME 常數(shù)值:1:這表明如此標記的(編碼的)緩沖區(qū)包含關鍵幀的數(shù)據(jù)。API 21中不贊成使用此常量。 使用BUFFER_FLAG_KEY_FRAME相反,都是關鍵幀

五、MediaExtractor和MediaMuxer結合的demo

實現(xiàn)音視頻的解封裝和封裝的過程:

//實現(xiàn)音視頻的解封裝和封裝的過程
public class MediaCodecDemo extends Activity {

    //顯示解封裝后的視頻和音頻在SD卡保存的位置
    private TextView tv_out;
    private final String mVideoPath = Environment.getExternalStorageDirectory()
                                     + "/Pictures/送孟浩然之廣陵.mp4";
    //解封裝和封裝在本地使用文件名
    private final String inputAudio = "audio1.aac";
    private final String outPutVideo = "video1.mp4";

    private static final String TAG1 ="解封裝MediaExtractor:" ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_media_codec);

        initView();
        //提取視頻分離出純音頻和純視頻文件
        extractorAndMuxerMP4(mVideoPath);
        //重新合成成音視頻文件
        muxerMp4(inputAudio,outPutVideo);
    }

    private void initView() {
        tv_out = findViewById(R.id.tv_out);
    }
}
//提取視頻分離出純音頻和純視頻文件
private void extractorAndMuxerMP4(String url){
    //提取數(shù)據(jù)(解封裝)
    //1. 構造MediaExtractor
    MediaExtractor mediaExtractor = new MediaExtractor();
    try {
        //2.設置數(shù)據(jù)源,數(shù)據(jù)源可以是本地文件地址,也可以是網(wǎng)絡地址:
        mediaExtractor.setDataSource(url);
        //3.獲取軌道數(shù)
        int trackCount = mediaExtractor.getTrackCount();
        //遍歷軌道,查看音頻軌或者視頻軌道信息
        for (int i = 0; i < trackCount; i++) {
            //4. 獲取某一軌道的媒體格式
            MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
            String keyMime = trackFormat.getString(MediaFormat.KEY_MIME);
            if (TextUtils.isEmpty(keyMime)) {
               continue;
            }
            //5.通過mime信息識別音軌或視頻軌道,打印相關信息
            //(默認的是先掃描到視頻,在掃描到音頻)
            if (keyMime.startsWith("video/")) {
                File outputFile = extractorAndMuxer(mediaExtractor, i, "/video.mp4");
                tv_out.setText("純視頻文件路徑:" + outputFile.getAbsolutePath());

            } else if (keyMime.startsWith("audio/")) {
                File outputFile = extractorAndMuxer(mediaExtractor, i, "/audio.aac");
                tv_out.setText(tv_out.getText().toString() + "\n純音頻路徑:" 
                                + outputFile.getAbsolutePath());
                tv_out.setVisibility(View.VISIBLE);
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

????????通過getTrackFormat(int index)來獲取各個track的MediaFormat,通過MediaFormat來獲取track的詳細信息,如:MimeType、分辨率、采樣頻率、幀率等等

    //確定是音軌或視頻軌道后,文件輸出
    private File extractorAndMuxer(MediaExtractor mediaExtractor, int i, String outputName) throws IOException{
        //獲取傳過來的MediaExtractor對應軌道的trackFormat
        MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
        MediaMuxer mediaMuxer;
        //選擇軌道
        mediaExtractor.selectTrack(i);

        File outputFile = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath() + outputName);
        if (outputFile.exists()) {
            //如果文件存在,就刪除
            outputFile.delete();
        }
        //1. 構造MediaMuxer
        mediaMuxer = new MediaMuxer(outputFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        //2. 添加軌道信息 參數(shù)為MediaFormat
        mediaMuxer.addTrack(trackFormat);
        //3. 開始合成
        mediaMuxer.start();
        //4. 設置buffer
        ByteBuffer buffer = ByteBuffer.allocate(500 * 1024);//設置每一幀的大小
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

        //5.通過mediaExtractor.readSampleData讀取數(shù)據(jù)流
        int sampleSize = 0;
        //循環(huán)讀取每幀的樣本數(shù)據(jù)
        //mediaExtractor.readSampleData(buffer, 0)把指定通道中的數(shù)據(jù)按偏移量讀取到ByteBuffer中
        while ((sampleSize = mediaExtractor.readSampleData(buffer, 0)) > 0) {
            bufferInfo.flags = mediaExtractor.getSampleFlags();
            bufferInfo.offset = 0;
            bufferInfo.size = sampleSize;
            bufferInfo.presentationTimeUs = mediaExtractor.getSampleTime();
            //所有解碼的幀都已渲染,我們現(xiàn)在可以停止播放了,雖然這里沒有用到
            //一般的使用方法是判斷 isEOS是否等于0;
            //int isEOS = bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM;
            //判斷輸出數(shù)據(jù)是否為關鍵幀的方法:
            //boolean keyFrame = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0;
            //6. 把通過mediaExtractor解封裝的數(shù)據(jù)通過writeSampleData寫入到對應的軌道
            mediaMuxer.writeSampleData(0, buffer, bufferInfo);
            //讀取下一幀數(shù)據(jù)
            mediaExtractor.advance();
        }
        Log.i(TAG1, "extractorAndMuxer: " + outputName + "提取封裝完成");

        mediaExtractor.unselectTrack(i);
        //6.關閉
        mediaMuxer.stop();
        mediaMuxer.release();
        return outputFile;
    }

這里需要科普一下兩個正數(shù)進行&運算:兩個正數(shù)進行&運算的值永遠小于或等于最小的數(shù)。

if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 
    Log.i(TAG, "OutputBuffer BUFFER_FLAG_END_OF_STREAM");       
    break;                                                      
}

????????我們知道BUFFER_FLAG_END_OF_STREAM代表的是2^2,也就是0100。因為是&運算,我們只用關注info.flags二進制第三位即可:為0即上面判斷為false,為1即上面判斷為true。

  • 正數(shù)與負數(shù)的與運算:負數(shù)的異或操作需要先把數(shù)轉換成補碼才行(頭不變取反+1)

兩個數(shù)互為相反數(shù)位與操作可有特殊用途,位與所剩恰為最低位。

兩個數(shù)互為相反數(shù)異或可能有特殊用途,異或后,所剩最低位左移一位。

到此我們就將音視頻解封裝成了音頻和視頻,并且保存在了指定文件當中,我們分析一下流程:

  1. 構造MediaExtractor(不需要參數(shù)) —> 之后的操作使用try/catch包圍 —> setDateSource(url)設置本地或者網(wǎng)絡資源?—> getTrackConut()獲取該資源的通道數(shù) —> for循環(huán)通道數(shù) —>?獲取某一軌道的媒體格式:getTrackFormat(i)返回一個MediaFormat?—>?判斷是什么通道根據(jù)trackFormat.getString(MediaFormat.KEY_MIME)返回ketMime的startsWith("?")?。
  2. 接下來的操作就確定了音軌和視頻軌道,同時確定文件的輸出地點。
  3. 構造MediaMuxer (需要指定文件和格式)—>?addTrack(trackFormat)添加軌道信息 參數(shù)為MediaFormat,注意這里的MediaFormat要是對應的軌道?—> start()開始合成?—>?設置ByteBuffer,用于緩存一幀數(shù)據(jù)?—>?MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo()獲取bufferInfo?—>?通過mediaExtractor.readSampleData讀取數(shù)據(jù)流,同時也作為一個while循環(huán)的判斷條件?—> 配置bufferInfo的四個屬性?—> 把通過mediaExtractor解封裝的數(shù)據(jù)通過mediaMuxer.writeSampleData寫入到對應的軌道?—> 讀取下一幀audioExtractor.advance()。
  4. 循環(huán)結束之后mediaExtractor.unselectTrack(i)釋放選擇?—>?mediaMuxer.stop()停止?—> 最后釋放mediaMuxer和mediaExtractor。

接下來我們開始合成操作。

    //把音軌和視頻軌再合成新的視頻
    private String muxerMp4(String inputAudio , String outPutVideo){
        File videoFile = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), "video.mp4");
        File audioFile = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), inputAudio);
        File outputFile = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), outPutVideo);


        if (outputFile.exists()) {
            outputFile.delete();
        }
        if (!videoFile.exists()) {
            Toast.makeText(this, "視頻源文件不存在", Toast.LENGTH_SHORT).show();
            return "";
        }
        if (!audioFile.exists()) {
            Toast.makeText(this, "音頻源文件不存在", Toast.LENGTH_SHORT).show();
            return "";
        }

        MediaExtractor videoExtractor = new MediaExtractor();
        MediaExtractor audioExtractor = new MediaExtractor();

        try {
            MediaMuxer mediaMuxer = new MediaMuxer(outputFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            int videoTrackIndex = 0;
            int audioTrackIndex = 0;

            //先添加視頻軌道
            videoExtractor.setDataSource(videoFile.getAbsolutePath());
            int trackCount = videoExtractor.getTrackCount();

            for (int i = 0; i < trackCount; i++) {
                MediaFormat trackFormat = videoExtractor.getTrackFormat(i);
                String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
                if (TextUtils.isEmpty(mimeType)) {
                    continue;
                }
                if (mimeType.startsWith("video/")) {
                    videoExtractor.selectTrack(i);

                    videoTrackIndex = mediaMuxer.addTrack(trackFormat);
                    break;
                }
            }

            //再添加音頻軌道
            audioExtractor.setDataSource(audioFile.getAbsolutePath());
            int trackCountAduio = audioExtractor.getTrackCount();
            for (int i = 0; i < trackCountAduio; i++) {
                MediaFormat trackFormat = audioExtractor.getTrackFormat(i);
                String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
                if (TextUtils.isEmpty(mimeType)) {
                    continue;
                }
                if (mimeType.startsWith("audio/")) {
                    audioExtractor.selectTrack(i);
                    audioTrackIndex = mediaMuxer.addTrack(trackFormat);
                    Log.i(TAG1, "muxerToMp4: audioTrackIndex=" + audioTrackIndex);
                    break;
                }
            }


            //再進行合成
            mediaMuxer.start();
            ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            int sampleSize = 0;

            while ((sampleSize = videoExtractor.readSampleData(byteBuffer, 0)) > 0) {

                bufferInfo.flags = videoExtractor.getSampleFlags();
                bufferInfo.offset = 0;
                bufferInfo.size = sampleSize;
                bufferInfo.presentationTimeUs = videoExtractor.getSampleTime();
                mediaMuxer.writeSampleData(videoTrackIndex, byteBuffer, bufferInfo);
                videoExtractor.advance();
            }

            int audioSampleSize = 0;

            MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();


            while ((audioSampleSize = audioExtractor.readSampleData(byteBuffer, 0)) > 0) {

                audioBufferInfo.flags = audioExtractor.getSampleFlags();
                audioBufferInfo.offset = 0;
                audioBufferInfo.size = audioSampleSize;
                audioBufferInfo.presentationTimeUs = audioExtractor.getSampleTime();
                mediaMuxer.writeSampleData(audioTrackIndex, byteBuffer, audioBufferInfo);
                audioExtractor.advance();
            }

            //最后釋放資源
            videoExtractor.release();
            audioExtractor.release();
            mediaMuxer.stop();
            mediaMuxer.release();

        } catch (IOException e) {
            e.printStackTrace();
            return "";

        }
        return outputFile.getAbsolutePath();
    }

????????因為這個與上面例子的流程大致相同,上面看懂了,下面基本上沒什么問題,所以注釋相對比較少。至于過程也就懶得分析了。

????????我們在解封裝的過程中同時使用到了MediaExtractor和MediaMuxer,包括合成的時候也用了這兩個。不要想當然的認為MediaExtractor解封裝出來兩文件,兩文件根據(jù)MediaMuxer就可以合成!??!

????????最后遺留兩個問題:

????????1.解封裝出來的是不同軌道的資源,可是當做文件輸出時,除了文件名不同其他的操作都是一模一樣,就連mediaMuxer的參數(shù)格式都是MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4,那音頻文件是怎樣合成成功的???

????????AAC代表Advanced Audio Coding(高級音頻編碼),是一種由MPEG-4標準定義的有損音頻壓縮格式。而且解封裝出來的音頻acc和視頻MP4改了后綴都可以正常播放。

????????

? ? ? ? 音頻文件同樣可以理解為一幀幀的說法,之后我回使用實時AAC音頻幀并通過AudioTrack來播放,盡情期待。

? ? ? ? 2.分解出來的軌道是固定的嗎?還是根據(jù)自定義來的?他的個數(shù)只能是一個音頻一個視頻嗎?文章來源地址http://www.zghlxwxcb.cn/news/detail-429527.html

  • 分解出來的軌道不是固定的但一般是兩個軌道(一個音頻一個視頻)
E/測試Demo: 軌道數(shù)量 = 2
E/測試Demo: 0編號通道格式 = video/avc
E/測試Demo: 1編號通道格式 = audio/mp4a-latm
  • 這個具體的順序就是根據(jù)你使用mediaMuxer添加合成的順序
  • 當然也可能有多個音頻和視頻在一個盒子里

到了這里,關于Android音視頻開發(fā)(三)——MediaExtractor和MediaMuxer的使用的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Android音視頻開發(fā)實戰(zhàn)02-Jni

    Android音視頻開發(fā)實戰(zhàn)02-Jni

    JNI是Java Native Interface的縮寫,是Java提供的一種機制,用于在Java代碼中調用本地(C/C++)代碼。它允許Java代碼與本地代碼進行交互,通過JNI,Java應用程序可以調用一些原生庫或者操作系統(tǒng)API,以獲取更好的性能和更強的功能支持。 使用JNI需要編寫一些Native方法,并將其實現(xiàn)在

    2024年02月11日
    瀏覽(30)
  • Android音視頻開發(fā)實戰(zhàn)01-環(huán)境搭建

    Android音視頻開發(fā)實戰(zhàn)01-環(huán)境搭建

    FFmpeg 是一款流行的開源多媒體處理工具,它可以用于轉換、編輯、錄制和流式傳輸音視頻文件。FFmpeg 具有廣泛的應用場景,包括視頻編解碼、格式轉換、裁剪、合并、濾鏡等等。官網(wǎng):https://ffmpeg.org/ FFmpeg 支持各種常見的音視頻格式,例如 MP4、AVI、FLV、MOV、AAC、MP3、M4A 等等

    2024年02月10日
    瀏覽(22)
  • Android 音視頻開發(fā)—MediaPlayer音頻與視頻的播放介紹

    Android 音視頻開發(fā)—MediaPlayer音頻與視頻的播放介紹

    Android多媒體中的——MediaPlayer,我們可以通過這個API來播放音頻和視頻該類是Androd多媒體框架中的一個重要組件,通過該類,我們可以以最小的步驟來獲取,解碼和播放音視頻。 它支持三種不同的媒體來源: 本地資源 內部的URI,比如你可以通過ContentResolver來獲取 外部URL(流

    2024年02月10日
    瀏覽(27)
  • 音視頻開發(fā)系列(6)——全面了解Android MediaFormat

    MediaFormat 是 Android 平臺中用于描述音視頻格式的類,它提供了許多 API 用于設置和獲取音視頻的格式信息。以下是 MediaFormat 類的主要 API: 用于創(chuàng)建音頻和視頻格式的 MediaFormat 對象。需要指定媒體類型(例如 audio/mp4a-latm 或 video/avc)、媒體的采樣率、通道數(shù)、碼率、幀率等信

    2024年02月01日
    瀏覽(28)
  • Android開源計劃-一周開發(fā)app,webrtc音視頻開發(fā)

    Android開源計劃-一周開發(fā)app,webrtc音視頻開發(fā)

    題目 – 一周開發(fā)app計劃 首批參與成員 -小巫 -墨香 -夢痕 -邊城刀客 -徐cc 要求 – -每位認領者按照開源規(guī)范來做,代碼規(guī)范和Android開發(fā)規(guī)范 -每位認領者必須擁有github賬號,熟練使用git對代碼進來管理 -每個人認領一個功能點或模塊 -提出完善的解決方案并提供封裝良好的庫

    2024年04月08日
    瀏覽(90)
  • Android 音視頻開發(fā)實踐系列-06-初步了解H.264視頻編解碼技術標準

    Android 音視頻開發(fā)實踐系列-06-初步了解H.264視頻編解碼技術標準

    本文來自筆者本人的語雀博客,由于語雀升級后不再滿足筆者的需求,因此之后筆者會陸續(xù)將一些之前已經(jīng)發(fā)布但尚有價值的文章搬家到CSDN。 作為音視頻行業(yè)從業(yè)者,怎么能不理解H.264視頻編解碼技術標準?本篇文章主要記錄筆者學習過程中對眾多優(yōu)秀博客內容的摘抄整理,

    2023年04月09日
    瀏覽(32)
  • 【學習】從零開發(fā)的Android音視頻開發(fā)(13)——MediaCodec到OMX框架過程及其硬解碼

    【學習】從零開發(fā)的Android音視頻開發(fā)(13)——MediaCodec到OMX框架過程及其硬解碼

    在講NuPlayer時,NuPlayer解碼部分會創(chuàng)建MediaCodec,并且最終到達OMX框架,先看MediaCodec的 init 函數(shù) 從init函數(shù)中可以看到,首先創(chuàng)建了 ACodec ,并且初始化了 ALooper 、 AMessage ,由于ACodec繼承自 AHandler ,那么一套消息機制就有了。最后發(fā)送 kWhatInit 消息,收到消息的邏輯位于ACodec.

    2023年04月08日
    瀏覽(32)
  • 音視頻開發(fā)之旅——音頻基礎概念、交叉編譯原理和實踐(LAME的交叉編譯)(Android)

    音視頻開發(fā)之旅——音頻基礎概念、交叉編譯原理和實踐(LAME的交叉編譯)(Android)

    本文章已授權微信公眾號郭霖(guolin_blog)轉載。 本文主要講解的是 音頻基礎概念 、 交叉編譯原理和實踐(LAME的交叉編譯) ,是基于 Android平臺 ,示例代碼如下所示: AndroidAudioDemo 另外, iOS平臺 也有相關的文章,如下所示: 音視頻開發(fā)之旅——音頻基礎概念、交叉編譯

    2024年04月25日
    瀏覽(34)
  • Android開發(fā)音視頻方向學習路線及資源分享,學完還怕什么互聯(lián)網(wǎng)寒冬?

    Android開發(fā)音視頻方向學習路線及資源分享,學完還怕什么互聯(lián)網(wǎng)寒冬?

    好了,回歸正題。 光看大綱,大家都知道要學習音視頻錄制,編碼,處理,但是具體不知道怎么做,也不知道怎么入門。我自己在入門的時候也一樣,靠著搜索引擎自己一點一點的積累,在這里當然要謝謝在該領域無私奉獻的大佬們。所以在這里,我會對知識進行細化,運用

    2024年04月11日
    瀏覽(29)
  • Android 短視頻直播特效,音視頻圖像處理 FFmepg OpenGLES OpenCV開發(fā)詳細內容

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包