概要
ビデオ ファイルには、いくつかの基本コンポーネントが含まれています。まず、ファイル自体はコンテナと呼ばれ、コンテナのタイプによってファイル内の情報の場所が決まります。AVI や Quicktime など。一連のストリームであり、通常はオーディオ ストリームとビデオ ストリームです。ストリーム内のデータ要素はフレームと呼ばれます。各ストリームは、異なる種類のコーデックによってエンコードされます。コーデックはデータのエンコードとデコードの方法を定義するため、コーデックという名前が付けられます。DivX や MP3 など。パケットは生のフレームにデコードできるデータを含むデータ フラグメントであり、各パケットには完全なフレームが含まれており、オーディオ ストリームの下に複数のフレームが含まれる場合もあります。
オーディオ データとビデオ データの処理は比較的単純ではなく、主に次の手順に分かれます。
10 ビデオ ファイルを開き、ストリームを取得します。
20 video_stram からデータ パケットを取得し、フレームに変換します。
30 フレームが読み込まれない場合は、実行を続行します。 20
40 フレーム を処理します
。 50 20 にジャンプします。
FFmpeg を使用してビデオを処理するのは非常に簡単です。この記事では、ビデオ ファイルのフレーム データを ppm 形式の画像として保存する方法を紹介します (ppm は、非常に単純なヘッダー情報と、残りのデータはすべて RGB データです)。
ファイルを開く
まず最初に、使用するライブラリを導入し、エラー出力関数を記述する必要があります。
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <libavformat/avformat.h>
#include <libavutil/error.h>
void showErrMsg(int errNum, char *msg, size_t msgSize) {
memset(msg, 0, msgSize);
av_strerror(errNum, msg, msgSize);
fprintf(stderr, msg);
}
この関数は、読みやすさを向上させるために FFmpeg 内のエラー コードを文字列に変換します。メイン関数は以下に記述されており、少なくとも 1 つのパラメータを渡す必要があり、パラメータはファイル パスとして開かれます。
fileName = argv[1];
if (argc < 2) {
fprintf(stderr, "Please use FFmpegDemo1 <file> to open a video file");
return -1;
}
if ((errNum = avformat_open_input(&pFormatCtx, fileName, NULL, NULL)) != 0) {
showErrMsg(errNum, errMsg, 400);
return -1;
}
av_register_all() 関数はバージョン 4 で非推奨になったため、情報を書き込む必要はありません。
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options)
この関数の機能は、URL が指すファイルを開くことです。
AVFormatContext
これは FFmepg の非常に重要な構造であり、Android のコンテキストに相当します。開発者がこの情報を簡単に取得できるように、FFmpeg の avformat のコンテキストを提供します。ただし、ここで渡されるポインタに注意してください。したがって、私たちの pFromatCtxAVFormatContext
はポインター、およびパラメーターを渡すときにポインターのポインターを渡す必要があります。
fmt はファイルの形式です。NULL を渡すと、FFmpeg はファイルのエンコード形式を自動的に判断し、
ヘッダー情報を読み取り、情報を表示します。
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
showErrMsg(errNum, errMsg, 400);
return -1;
}
av_dump_format(pFormatCtx, 0, fileName, 0);
avformat_find_stream_info
この関数は、ファイルのストリームの情報を読み取りpFormatCtx->streams
、av_dump_format
関数を通じてこれらの詳細を出力します。
テストファイル出力の詳細は以下のとおりです。
Input #0, matroska,webm, from '../in.mkv':
Metadata:
title : www.*********.com
encoder : libebml v1.2.3 + libmatroska v1.3.0
creation_time : 2012-06-30T02:28:33.000000Z
Duration: 00:25:43.08, start: 0.000000, bitrate: 1311 kb/s
Chapter #0:0: start 0.105000, end 1543.082000
Metadata:
title : 00:00:00.105
Stream #0:0: Video: h264 (High), yuv420p(progressive), 1440x1080 [SAR 1:1 DAR 4:3], 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)
Stream #0:1(jpn): Audio: aac (LC), 48000 Hz, stereo, fltp
Metadata:
title : 日语
Stream #0:2(chi): Audio: aac (HE-AAC), 44100 Hz, stereo, fltp (default)
Metadata:
title : 国语
Stream #0:3: Subtitle: subrip (default)
ビデオ ファイルには、ビデオ ストリームとオーディオ ストリームなどの多くのストリームが含まれており、オーディオ ストリームには複数の音声が含まれる場合があります。たとえば、上記の出力情報では、ビデオ ストリームは stream0 で、オーディオ ストリームには 2 つのストリーム (stream1 日本語) が含まれています。 stream2. 中国語。この記事の目的は、ビデオ ストリームをフレームに分解し、最初の 50 フレームの情報を保存することです。次に、対応するビデオ ストリームを見つける必要があります。コードは次のとおりです。
pFormatCtx的streams
すべてのフロー情報は に保存され、AVCodecParameters
この構造は に保存されAVMediaType
、この列挙クラスはフローのタイプになります。
AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA
AVMEDIA_TYPE_VIDEO,
AVMEDIA_TYPE_AUDIO,
AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous
AVMEDIA_TYPE_SUBTITLE,
AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse
AVMEDIA_TYPE_NB
トラバースする必要があるのは、ビデオ ストリームを見つけて保存してAVCodecParameters
インデックスを作成することだけです。1つAVCodecParameters
だけでなくAVMediaType
、もう 1 つありますAVCodecID
。この列挙クラスは、ビデオ ファイルのエンコード方法を保存します。この ID に従って、対応するデコーダを見つける必要があります。 :
pCodec = avcodec_find_decoder(codecPar->codec_id);
if (pCodec == NULL) {
fprintf(stderr, "Unsupported codec!");
return -1;
}
デコーダを検索した後、デコーダの関連コンテンツを初期化する必要があります。これは主に liaavcodec ライブラリによって行われ、コンテキストも必要です。
pCodecCtx = avcodec_alloc_context3(pCodec);
avcodec_parameters_to_context(pCodecCtx, codecPar);
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
return -1;
}
上記のコードでは、pCodecCtx
まず に領域を割り当て、そこに先ほどの codecPar パラメータを渡してpCodecCtx
対応するパラメータに設定し、avcodec_open2
pCodecCtx を初期化し、デコーダを開く作業が完了します。
情報処理
最も単純な分析図を作成しました。
まず、いくつかのデータ構造を初期化する必要があります
pFrame = av_frame_alloc();
AVFrame *pFrameRGB = av_frame_alloc();
if (pFrameRGB == NULL) {
return -1;
}
unsigned char *buffer = NULL;
int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height,AV_INPUT_BUFFER_PADDING_SIZE);buffer = (unsigned char *) av_malloc(numBytes * sizeof(unsigned char));
av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height, AV_INPUT_BUFFER_PADDING_SIZE);
struct SwsContext *sws_ctx = NULL;
AVPacket packet;
sws_ctx = sws_getContext(pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
AV_PIX_FMT_RGB24,
SWS_BILINEAR,
NULL, NULL, NULL);
i = 0;
pFrameはデコードされた元のデータを格納するための構造体で、図のpFrame(empty)とpFrame(full)に相当し、pFrameRGBはSwsContextによって変換されたデータで、図のpFrame(tosave)に相当し、直接格納できます。画像としての pFrameRGB。Buffer は配列へのポインタであり、pFrameRGB のデータ領域を提供するために使用されます。SwsContext は、単純に画像を拡大縮小するために使用される libswscale のコンテキストです。
次にデータを処理する必要があります。
1 つ目は、av_read_frame
video_stream のデータをパケットに読み取り、そのパケットをavcodec_send_packet
AVCodecContext に送信し、AVCodecContext がデータを元の画像データ フレームにデコードします。avcodec_receive_frame
デコードされたフレームを SWScaleContext を通じて取得し、画像を渡します。 SWScaleContext を介したデータ rgb 形式でフォーマットされており、最後にパケットを連続的に解放する必要がありますが、ここで注意していただきたいのは、相互に 1 対 1 の対応関係がないこと、つまり、データを入力した後にデータを出力する必要がないことですavcodec_send_packet
。複数のフレームのデータがキャッシュされる可能性があるavcodec_receive_frame
ためです。AVCodecContext
セーブデータ
データの保存は比較的簡単です。コードを見てください。
リソースを解放する
FFMpeg で割り当てられたリソースのほとんどは、1 つずつ呼び出すことができる単純な解放メソッドを提供します。
av_free(buffer);
av_frame_unref(pFrameRGB);
av_frame_unref(pFrame);
av_free(pFrame);
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
プロジェクトを実行する
まず、次の cmake ファイルを構成します。
pthread がインストールされていない場合は、最初に pthread をインストールする必要があります。そうしないとプログラムは実行できません。また、ライブラリのリンク順序にも注意する必要があります。
pthread のインストールコードは次のとおりです。
sudo apt-get install glibc-doc
sudo apt-get install manpages-posix-dev
clion の実行機能を直接使用してプログラムを実行できますが、最初にビデオ ファイルのパスをパラメーターとして追加します。また、ファイル ファイルを直接生成してコマンド ラインで実行することもできます。
mkdir build;cd build/ \\执行外部构建
cmake ..
make
FFmpegDemo1 ../in.mkv
実行が完了すると、生成された ppm ファイルが表示され、clion はそれを直接開くことができます。
オリジナルの FFmpeg 学習 1 - ビデオを画像としてインターセプト - Nuggets
★記事末尾の名刺では、オーディオ・ビデオ開発学習教材(FFmpeg、webRTC、rtmp、hls、rtsp、ffplay、srs)やオーディオ・ビデオ学習ロードマップ等を無料で受け取ることができます。
下記参照!