robot
最新文章(10)
Mqskit 和其它相關工具
CPython 的 GC 二、三事
寫 Mecurial Extension 是件快樂的事!
Mozilla 台灣辨公室徵人啟事
關於 Apple 的兩項專利
core dump 之前的 frame
怎麼發出 beep 聲?
先承認你要找的是奴才吧!
程式碼要清的多乾淨?
FreeBSD 的 Thread-Local Storage 實作
首頁
新編
最新留言
Entries RSS
重要關鍵字(10)
coding (122)
Python (93)
FreeBSD (71)
WEB (61)
URL (48)
hardware (46)
javascript (36)
Linux (34)
blog (30)
C++ (16)
所有關鍵字
新增 URL
FFmpeg 使用筆記
by thinker
2 Columns
關鍵字:
coding
linkname:FFmpeg http://www.ffmpeg.org/ 是一個 open source 的影音媒體編碼/解碼軟體和程式庫,實作各式各樣格式的 codec,包括常的 AVI 、 WMV 、 WMA ...... 等等。 === AVInputFormat/AVOutputFormat === multimedia 檔案的 Muxer/Demuxer ,將多個 stream;如 auodi 、video 等,以單個媒體承載。媒體可以是檔案、 $network$ session 等等。每一個 AVFormat 代表一種格式,像是 .avi 、 .wmv 、 .dat 等等各種格式,使用不同的方式 mux/demux 多個 stream。每一 AVFormat 都實作特定的格式,使用時必需選擇和目的格式相符的 AVFormat 實作,才能正確的讀取 stream 的內容。 === AVFormatContext === AVFormatContext 是 AVFormat 的一個 instance ,用以存放 AVFormat 的執行狀態。使用 FFmpeg 處理檔案時,必需為 AVInputFormat/AVOutputFormat 建立一個 AVFormatContext 。同一個 format 可以建立多個 AVFormatContext ,各立獨立,不相互干擾,以同時處理多個檔案。 === AVStream === AVStream 用以對應到 AVFormatContext 裡的一個 stream 。因此同一個 AVFormatContext 管理了多個 AVStream ,以對應到存在檔案或透過 $network$ session 傳送的數個 stream。 === AVPacket === 在 stream 裡的資料,是以 packet 為單位進行傳送/儲存。因此,一般多媒體檔,是將檔案當成 $network$ session 一般處理。每一個 AVPacket 標注了所屬的 stream ,透過 AVPacket 的包裝,多個 stream 可以同時在一個媒介上傳送/儲存。因此,我們可以讀 stream 是由一系列的 packet 所組成。 === AVCodec === 一個影音媒體檔裡,可以承載多個 stream。而 stream 內有 packet。 packet 的 payload ,也就是資料,是透過 codec 編碼/壓縮的。因此,必需透過 codec 進行讀取/寫入時的 decode/encode。AVCodec 就是實作 codec 演算法。同樣的,codec 的演算法有各式各樣。使用時,必需選正確的 AVCodec ,才能正確的 decode/encode。 === AVCodecContext === AVCodecContext 是 AVCodec 的一個 instance ,用以存放 AVCodec 的執行狀態。同樣可以建立多個 AVCodecContext ,同時處理多個相同格式、不同格式的 stream 。 === AVFrame === AVFrame 的頭幾個欄位和 AVPicture 相同,也就是 AVPicture 為 AVFrame 的一小部分。 === 寫入多媒體檔 === 步驟 * select an AVFormat * allocate a AVFormatContext * initialize AVFormatContext with selected AVFormat * create and initialize an AVStream with SVGFormatContext and codec_id specified by AVFormat * AVStream::codec is AVCodecContext * initialize AVCodecContext with the AVCodec specified by codec_id * avcodec_open() * initialize output stream of AVFormatContext * av_write_header() * write frames * create an AVFrame * initialize an AVPacket with AVFrame * av_write_frame() * close streams * av_write_trailer() * free streams * close output stream * free AVFromatContext === 讀取多媒體檔 === 產生檔案時,目的格式是由我們所選擇,因此問題往往較單純一點。但讀取檔案時,我們不確定檔案的格式,必需進行格式判斷後,才確定使用哪一個 AVInputFormat 。 * av_open_input_file() * Read probe buffer * get_buffer() * av_probe_input_format() or av_probe_input_format2() * return AVFormat * Allocate AVFormatContext * av_open_input_stream() * av_find_stream_info * setup codec for streams * avcodec_find_decoder() * avcodec_open() * 讀取 frames * av_read_frame() * prepare an AVFrame * avcodec_get_frame_defaults() * decode the frame in pkt to AVFrame * avcodec_decode_video() * got_picture is true if a picture being returned by the AVFrame. * close codec === 影片讀取$範例$ === {{{#!cpp #include <stdio.h>; #include <string.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> int main(int argc, const char *argv[]) { const char *fname; AVFormatContext *ic; AVStream *is, *tis; AVCodec *codec; AVFormatParameters params, *ap = ¶ms; AVPacket pkt; AVFrame frame; AVPicture *pic; int got_picture; int i, r; av_register_all(); if(argc != 2) { fprintf(stderr, "Usage: %s <media file>\n", argv[0]); return 1; } fname = argv[1]; memset(ap, 0, sizeof(AVFormatParameters)); ap->video_codec_id = CODEC_ID_NONE; printf("codec id %X\n", ap->video_codec_id); r = av_open_input_file(&ic, fname, NULL, 0, ap); if(r != 0 || ic == NULL) { fprintf(stderr, "can not open input file %s\n", fname); return 1; } av_find_stream_info(ic); is = NULL; for(i = 0; i < ic->nb_streams; i++) { tis = ic->streams[i]; if(tis->codec->codec_type == CODEC_TYPE_VIDEO) { printf("channel %d of %d\n", i, ic->nb_streams); is = tis; } } codec = avcodec_find_decoder(is->codec->codec_id); if(codec == NULL) { fprintf(stderr, "can not find codec %s\n", is->codec->codec_name); return 1; } r = avcodec_open(is->codec, codec); if(r != 0) { fprintf(stderr, "can not initialize a AVCodecContext for codec %s\n", codec->name); return 1; } printf("Codec %s (%d x %d)\n", codec->name, is->codec->width, is->codec->height); for(i = 0; i < 10;) { r = av_read_frame(ic, &pkt); if(r != 0) { fprintf(stderr, "no more frame\n"); return 1; } if(pkt.stream_index != is->index) continue; if(pkt.pts != AV_NOPTS_VALUE) printf("Frame %d@%d: pts=%lld, dts=%lld, size=%d, data=%x\n", i, pkt.stream_index, pkt.pts, pkt.dts, pkt.size, pkt.data); else printf("Frame %d@%d: pts=N/A, dts=%lld, size=%d, data=%x\n", i, pkt.stream_index, pkt.dts, pkt.size, pkt.data); av_pkt_dump(stdout, &pkt, 0); avcodec_get_frame_defaults(&frame); r = avcodec_decode_video(is->codec, &frame, &got_picture, pkt.data, pkt.size); if(r < 0) { printf("decoding error\n"); return 1; } if(got_picture) { printf("\tlinesize[4]={%d %d %d %d}, data[4]={%x %x %x %x)}\n", frame.linesize[0], frame.linesize[1], frame.linesize[2], frame.linesize[3], frame.data[0], frame.data[1], frame.data[2], frame.data[3]); } av_free_packet(&pkt); i++; } avcodec_close(is->codec); return 0; } }}} compile it {{{#!raw gcc -o mminfo mminfo.c -I/usr/local/include -lavformat -lavcodec -L/usr/local/lib }}}
最後更新時間: 2009-09-14 14:06:06 CST |
引用
查詢:
COMMENTS: