1. 程式人生 > >FFMPEG基於記憶體的轉碼例項

FFMPEG基於記憶體的轉碼例項

/** 他山之石,學習為主,版權所無,翻版不究,有錯無責 基於記憶體的格式封裝測試 使用 ./a.out a.avi a.mkv 支援的: avi mkv mp4 flv ts ... 參考: http://blog.csdn.net/leixiaohua1020/article/details/25422685 log 新版本出現: Using AVStream.codec.time_base as a timebase hint to the muxer is  deprecated. Set AVStream.time_base instead. test passed!! mp4->avi failed 出現: H.264 bitstream malformed, no startcode found, use the h264_mp4toannexb bitstream filter  解決見: http://blog.chinaunix.net/uid-11344913-id-4432752.html 官方解釋: https://www.ffmpeg.org/ffmpeg-bitstream-filters.html#h264_005fmp4toannexb ts -> avi passed 其它: 1、自定USE_MEM,則轉換後的資料在記憶體中,要用write將其寫回到檔案    如果不定義,則每一次write都會寫到檔案,seek也是檔案操作 2、傳遞給ffmpeg的avio_alloc_context中的記憶體p和大小size,可以使用32768。 如果轉換後的資料儲存在記憶體p1,這個記憶體p1一定要和前面所說的p不同。因為 在自定義的write中的buf引數,就是p,所以要拷貝到其它記憶體。 如定義p為32768,但定義p1為50MB,可以轉換50MB的視訊 測試: p為32768時,需呼叫write 1351次 2倍大小時,呼叫write 679次 p越大,呼叫次數最少,記憶體消耗越大 (用time測試,時間上沒什麼變化,前者為4.7s,後者為4.6s) 3、優化:    轉換功能介面封裝為類,把write、seek等和記憶體有關的操作放到類外部實現,    再傳遞到該類中,該類沒有記憶體管理更好一些。 */
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" } #ifndef min #define min(a,b) ((a) > (b) ? (b) : (a)) #endif
#define _LL_DEBUG_ // low level debug #ifdef _LL_DEBUG_     #define debug(fmt, ...) printf(fmt, ##__VA_ARGS__)     #define LL_DEBUG(fmt, ...) printf("[DEBUG %s().%d @ %s]: " fmt, \     __func__, __LINE__, P_SRC, ##__VA_ARGS__) #else     #define debug(fmt, ...)     #define LL_DEBUG(fmt, ...) #endif // 自定義的IO全部在記憶體
#define USE_MEM #define DEFAULT_MEM (10*1024*1024) #define IO_BUFFER_SIZE (32768*1) static char g_ptr1[IO_BUFFER_SIZE] = {0}; static char* g_ptr = NULL; //static char g_ptr[DEFAULT_MEM] = {0}; static int g_nPos = 0; static int g_nTotalLen = DEFAULT_MEM; static int g_nRealLen = 0; static int g_fd = 0; int my_read(void *opaque, unsigned char *buf, int buf_size) {     // no     return 0; } int my_write(void *opaque, unsigned char *buf, int size) {     if (g_nPos + size > g_nTotalLen)     {         // 重新申請         // 根據數值逐步加大         int nTotalLen = g_nTotalLen*sizeof(char) * 3 / 2;         char* ptr = (char*)av_realloc(g_ptr, nTotalLen);         if (ptr == NULL)         { // if (g_ptr) av_free(g_ptr);             return -1;         }         debug("org ptr: %p new ptr: %p size: %d(%0.fMB) ", g_ptr, ptr,                      nTotalLen, nTotalLen/1024.0/1024.0);         g_nTotalLen = nTotalLen;         g_ptr = ptr;         debug(" realloc!!!!!!!!!!!!!!!!!!!!!!!\n");         // todo         //memcpy(g_ptr + g_nPos, buf, size);     }     memcpy(g_ptr + g_nPos, buf, size);     if (g_nPos + size >= g_nRealLen)         g_nRealLen += size;          static int cnt = 1;     debug("%d write %p %p pos: %d len: %d\n", cnt++, g_ptr, buf, g_nPos, size);     //dump("org ", (char*)buf, 32);     //dump("g_ptr ", g_ptr, 32);          g_nPos += size;     return 0; } int64_t my_seek(void *opaque, int64_t offset, int whence) {     int64_t new_pos = 0// 可以為負數     int64_t fake_pos = 0;     switch (whence)     {         case SEEK_SET:             new_pos = offset;             break;         case SEEK_CUR:             new_pos = g_nPos + offset;             break;         case SEEK_END: // 此處可能有問題             new_pos = g_nTotalLen + offset;             break;         default:             return -1;     }          fake_pos = min(new_pos, g_nTotalLen);     if (fake_pos != g_nPos)     {         g_nPos = fake_pos;     }     debug("seek pos: %d(%d)\n", offset, g_nPos);     return new_pos; } int my_write1(void *opaque, unsigned char *buf, int size) {     debug("write %p len: %d\n",  buf, size);     //dump("org ", (char*)buf, 32);     //dump("g_ptr ", (char*)g_ptr, 32);     return write(g_fd, buf, size); } int64_t my_seek1(void *opaque, int64_t offset, int whence) {     debug("seek pos: %d whence: %d\n", offset, whence);     return lseek(g_fd, offset, whence); } // 定義2個函式指標,免得後面改 static int (*write_packet)(void *opaque, uint8_t *buf, int buf_size) =  #ifdef USE_MEM my_write #else my_write1 #endif ; static int64_t (*seek)(void *opaque, int64_t offset, int whence) = #ifdef USE_MEM my_seek #else my_seek1 #endif ; int remuxer_mem(int argc, char* argv[]) {     //輸入對應一個AVFormatContext,輸出對應一個AVFormatContext     //(Input AVFormatContext and Output AVFormatContext)     AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;     AVPacket pkt;     const char *in_filename, *out_filename;     int ret = 0;     AVIOContext *avio_out = NULL;      if (argc < 3)     {         printf("usage: %s [input file] [output file]\n", argv[0]);         printf("eg %s foo.avi bar.ts\n", argv[0]);         return -1;     }     in_filename  = argv[1];     out_filename = argv[2];     // 分配空間     g_ptr = (char*)av_realloc(NULL, DEFAULT_MEM*sizeof(char));  // new     if (g_ptr == NULL)     {         debug("alloc mem failed.\n");         return -1;     }     printf("------alloc ptr: %p\n", g_ptr);     memset(g_ptr, '\0', DEFAULT_MEM);     av_register_all();     //輸入(Input)     if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 00)) < 0)     {         printf( "Could not open input file '%s': %s\n", in_filename, strerror(errno));         goto end;     }     if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0)     {         printf( "Failed to retrieve input stream information\n");         goto end;     }     printf("input format:\n");     av_dump_format(ifmt_ctx, 0, in_filename, 0);     //輸出(Output)          // 先開啟要儲存的檔案     g_fd = open(out_filename, O_CREAT|O_RDWR, 0666);          // 分配自定義的AVIOContext     // 注意,參考file協議的記憶體,使用大小32768,而g_ptr是不同一片記憶體的     avio_out =avio_alloc_context((unsigned char *)g_ptr1, IO_BUFFER_SIZE, 1,                 NULL, NULL, write_packet, seek);      if (!avio_out)     {         printf( "avio_alloc_context failed\n");         ret = AVERROR_UNKNOWN;         goto end;     }     // 分配AVFormatContext     // out_filename 根據輸出副檔名來判斷格式     // 注意該函式會分配AVOutputFormat     avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);     if (!ofmt_ctx)     {         printf( "Could not create output context\n");         ret = AVERROR_UNKNOWN;         goto end;     }     ofmt_ctx->pb=avio_out; // 賦值自定義的IO結構體     ofmt_ctx->flags=AVFMT_FLAG_CUSTOM_IO; // 指定為自定義     debug("guess format: %s(%s) flag: %d\n", ofmt_ctx->oformat->name,              ofmt_ctx->oformat->long_name, ofmt_ctx->oformat->flags);     for (int i = 0; i < (int)ifmt_ctx->nb_streams; i++)     {         //根據輸入流建立輸出流(Create output AVStream according to input AVStream)         AVStream *in_stream = ifmt_ctx->streams[i];         AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);         if (!out_stream)         {             printf( "Failed allocating output stream\n");             ret = AVERROR_UNKNOWN;             goto end;         }         //複製AVCodecContext的設定(Copy the settings of AVCodecContext)         ret = avcodec_copy_context(out_stream->codec, in_stream->codec);         if (ret < 0)         {             printf( "Failed to copy context from input to output stream codec context\n");             goto end;         }         out_stream->codec->codec_tag = 0;         if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)             out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;     }     //輸出一下格式------------------     printf("output format:\n");     av_dump_format(ofmt_ctx, 0, out_filename, 1);     //開啟輸出檔案(Open output file)     // !!!! 存在於記憶體,不需要明確指定開啟,這種形式是針對檔案或網路協議的     /*     if (!(ofmt->flags & AVFMT_NOFILE))     {         ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);         if (ret < 0)         {             printf( "Could not open output file '%s': %s\n", out_filename, strerror(errno));             goto end;         }     }     */     //寫檔案頭(Write file header)     ret = avformat_write_header(ofmt_ctx, NULL);     if (ret < 0)     {         printf( "Error occurred when opening output file\n");         goto end;     }     while (1)     {         AVStream *in_stream, *out_stream;         //獲取一個AVPacket(Get an AVPacket)         ret = av_read_frame(ifmt_ctx, &pkt);         if (ret < 0)             break;         in_stream  = ifmt_ctx->streams[pkt.stream_index];         out_stream = ofmt_ctx->streams[pkt.stream_index];         /* copy packet */         //轉換PTS/DTS(Convert PTS/DTS)         pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base,              out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));         pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base,             out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));         pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);         pkt.pos = -1;         //寫入(Write)         ret = av_interleaved_write_frame(ofmt_ctx, &pkt);         if (ret < 0) {             printf( "Error muxing packet\n");             break;         }         av_free_packet(&pkt);     }     //寫檔案尾(Write file trailer)     av_write_trailer(ofmt_ctx); end:     avformat_close_input(&ifmt_ctx);     avformat_free_context(ofmt_ctx);     #ifdef USE_MEM     write(g_fd, g_ptr, g_nRealLen);     #endif     av_freep(&avio_out);     av_freep(&g_ptr);     close(g_fd);     return ret; }

相關推薦

FFMPEG基於記憶體例項

/** 他山之石,學習為主,版權所無,翻版不究,有錯無責 基於記憶體的格式封裝測試 使用 ./a.out a.avi a.mkv 支援的: avi mkv mp4 flv ts ... 參考: http://blog.csdn.net/leixiaohua1020/article/details/25

黃聰:FFmpeg視頻技巧之-crf參數(H.264篇)

文件中 one log 它的 忽略 enter center tail vcd 昨天,有個朋友給我出了個難題:他手上有一個視頻,1080P的,49秒,200多兆;要求在確保質量的情況下把文件壓縮到10M以內。 這是什麽概念呢?按照文件大小10M來計算,碼率是:10 x 8

FFMPEG實現的程序

enc yuv sso oba avstream med ext lin repl 本例子是由FFEMPG的doc/example例子transcode.c修改而來,可以根據需求任意轉換音視頻的編碼。 原來的例子的作用更類似於remux,並沒有實現轉碼的功能,只是實

C# 使用 ffmpeg 進行音訊

先放一下 ffmpeg 的官方文件以及下載地址: 官方文件:http://ffmpeg.org/ffmpeg.html 下載地址:http://ffmpeg.org/download.html 用 ffmpeg 進行轉碼很簡單,全部都用預設引數的話用下面這句就行: ff

ffmpeg任意格式為M4A

$ffmpeg = 'bin/ffmpeg-2.8-64bit-static/ffmpeg'; $neroAacEnc = 'bin/NeroAACCodec-1.5.1/linux/neroAacEnc'; $input = "a.mp3"; $rate = 320000; $outp

圖片基於base64技術

1、型別宣告+base64轉碼資料 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</tit

瀏覽器音訊相容和ffmpeg的音訊使用

1、百度搜索瀏覽器對於音訊檔案的相容,排在前面的文章大部分是複製貼上很久以前的文章,容易誤導搜尋資料的人, 因此重新驗證整理下。   以Firefox瀏覽器為例,Firefox對於mp3格式音訊的支援在釋出版本21時就已經支援了(2013年)。 下載Firefox各個版本,然後在audio標籤上引入mp3

js 基於base64上傳圖片

function imgChange(obj1, obj2){         var file = document.getElementById("file");         var imgContainer = document.getElementsByClas

FFmpeg:視訊、剪下、合併、播放速調整

安裝去官網按提示安裝即可,支援三大作業系統。唯一要吐槽的是,Ubuntu 14.04 等較新的版本,從預設軟體列表裡移除了 ffmpeg,轉而支援 libav,可是 libav 又沒弄好,很難用——開源社群瞎折騰起來真是無力吐槽。2017 更新: Ubuntu 16.04,F

FFmpeg命令列

本文主要了解FFmpeg進行音視訊編碼轉換。主要學習如下幾個知識點: FFmpeg使用libx264進行H,264(AVC)軟編碼,使用libx265進行H.265(HEVC)軟編碼 使用FFmpeg在MacOS環境下硬編碼 瞭解音訊編碼,MP3,AAC的引

最簡單的基於FFMPEG程式

                本文介紹一個簡單的基於FFmpeg的轉碼器。它可以將一種視訊格式(包括封轉格式和編碼格式)轉換為另一種視訊格式。轉碼器在視音訊編解碼處理的程式中,屬於一個比較複雜的東西。因為它結合了視訊的解碼和編碼。一個視訊播放器,一般只包含解碼功能;一個視訊編碼工具,一般只包含編碼功能;而一

最簡單的基於FFmpeg的移動端例子:Android 視訊

=====================================================最簡單的基於FFmpeg的移動端例子系列文章列表:=====================================================本文記錄一個安

ffmpegflv到avi《

音頻 編碼器 nbsp 結合 獲得 獲取 src 流程 img 一個視頻轉碼器,則需要對視頻進行解碼,然後再對視頻進行編碼,因而相當於解碼器和編碼器的結合。 下面圖列舉了一個視頻的轉碼流程。 輸入的視頻封裝格式是flv 視頻編碼標準是H.264 音頻編碼標準是AAC;

ffmpeg本地文件(一)

name range ams 單身男女 img 不同 字符 codec glob ffmpeg轉碼本地文件(一) 實現目標:輸入本地文件。實現本地文件轉碼,裏面包括mux層轉碼,codec層轉碼,視頻格式轉換,音頻重採樣等功能,功能點請看凝視。註意:凝視非常重要。

視頻:linux下ffmpeg 實現視頻

視頻轉碼使用shell快速安裝視頻轉碼器 #!/bin/bash #1、保證系統可以連到外網,需要下載安裝包和依賴包 #2、依賴gcc編譯器 #3、測試命令:ffmpeg -i test.avi out.mp4 set -e ffmDir="/usr/myapp" ffmVer="ffmpeg-3.4.1

使用ffmpeg時遇到aac報錯

允許 aac 實驗 解碼器 inf 錯誤 ffmpeg 視頻 ant 今天嘗試用ffmpeg轉一個視頻的格式,結果報出這個錯誤: The encoder 'aac' is experimental but experimental codecs are n

】使用ffmpeg的MP4文件需要加載完了才能播放的解決辦法

處理 輸出 方案 文件頭部 size ide mp4 sdn 才會 1、前一段時間做了一個ffmpeg轉碼MP4的項目,但是轉出來的MP4部署在網站上需要把整個視頻加載完成才能播放,到處找資料,最後找到解決方案記錄於此備忘。 FFMpeg轉碼由此得到的mp4文件中, m

FFmpeg:視頻、剪切、合並、播放速調整

基本上 不安裝 同時 using 上傳 lis got 轉碼 導師 原文:https://fzheng.me/2016/01/08/ffmpeg/ FFmpeg:視頻轉碼、剪切、合並、播放速調整 2016-01-08 前陣子幫導師處理項目 ppt,因為插入視頻的格式問題被搞

FFmpeg簡單程序--視頻剪輯

read all 解碼 num avs key iba yuv start 學習了雷神的文章,慕斯人分享精神,感其英年而逝,不勝唏噓。他有分享一個轉碼程序《最簡單的基於FFMPEG的轉碼程序》其中使用了filter(參考了ffmpeg.c中的流程),他曾說想再編寫一個

ffmpeg和mencoder實現視訊

  最近研究了一下視訊轉碼的問題,參考了部落格https://blog.csdn.net/wdy_2099/article/details/71453602?utm_source=blogxgwz3 具體內容這裡不再說了,安裝可參考https://www.cnblogs.com/new-ass/p/7704