C# - ffmpeg(FFmpeg.AutoGen)를 이용한 avio_reading.c 예제 포팅
지난 예제에 이어,
C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 프레임의 크기 및 포맷 변경 예제(scaling_video.c)
; https://www.sysnet.pe.kr/2/0/12961
이번에는
ffmpeg 예제 중 "
avio_reading.c" 파일을 FFmpeg.AutoGen으로 포팅하겠습니다.
using FFmpeg.AutoGen;
using FFmpeg.AutoGen.Example;
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace FFmpegApp1
{
internal unsafe class Program
{
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
static extern void MoveMemory(IntPtr dest, IntPtr src, int size);
static unsafe int Main(string[] args)
{
FFmpegBinariesHelper.RegisterFFmpegBinaries();
#if DEBUG
Console.WriteLine("Current directory: " + Environment.CurrentDirectory);
Console.WriteLine("Running in {0}-bit mode.", Environment.Is64BitProcess ? "64" : "32");
Console.WriteLine($"FFmpeg version info: {ffmpeg.av_version_info()}");
#endif
Console.WriteLine();
AVFormatContext* fmt_ctx = null;
AVIOContext* avio_ctx = null;
byte* buffer = null;
byte* avio_ctx_buffer = null;
ulong buffer_size;
ulong avio_ctx_buffer_size = 4096;
int ret = 0;
buffer_data bd = new buffer_data();
string input_filename = @"D:\media_sample\test.mkv";
ret = ffmpeg.av_file_map(input_filename, &buffer, &buffer_size, 0, null);
if (ret < 0)
{
return ret;
}
bd.ptr = buffer;
bd.size = (int)buffer_size;
do
{
fmt_ctx = ffmpeg.avformat_alloc_context();
if (fmt_ctx == null)
{
ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
break;
}
avio_ctx_buffer = (byte*)ffmpeg.av_malloc(avio_ctx_buffer_size);
if (avio_ctx_buffer == null)
{
ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
break;
}
avio_ctx = ffmpeg.avio_alloc_context(avio_ctx_buffer, (int)avio_ctx_buffer_size, 0, &bd,
(avio_alloc_context_read_packet_func)read_packet, null, null);
if (avio_ctx == null)
{
ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
break;
}
fmt_ctx->pb = avio_ctx;
ret = ffmpeg.avformat_open_input(&fmt_ctx, null, null, null);
if (ret < 0)
{
Console.WriteLine("Could not open input");
break;
}
ret = ffmpeg.avformat_find_stream_info(fmt_ctx, null);
if (ret < 0)
{
Console.WriteLine("Could not find stream information");
break;
}
ffmpeg.av_dump_format(fmt_ctx, 0, input_filename, 0);
} while (false);
if (fmt_ctx != null)
{
ffmpeg.avformat_close_input(&fmt_ctx);
}
if (avio_ctx != null)
{
ffmpeg.av_freep(&avio_ctx->buffer);
ffmpeg.avio_context_free(&avio_ctx);
}
ffmpeg.av_file_unmap(buffer, buffer_size);
return ret;
}
static unsafe int read_packet(void *opaque, byte* buf, int buf_size)
{
buffer_data* bd = (buffer_data*)opaque;
buf_size = (int)Math.Min(buf_size, bd->size);
if (buf_size == 0)
{
return ffmpeg.AVERROR_EOF;
}
Console.WriteLine($"ptr:{new IntPtr(bd->ptr):x} size:{bd->size}");
MoveMemory(new IntPtr(buf), new IntPtr(bd->ptr), buf_size);
bd->ptr += buf_size;
bd->size -= buf_size;
return buf_size;
}
}
public unsafe struct buffer_data
{
public byte* ptr;
public int size;
}
}
이런 식의 제어가 언제 필요한지는 모르겠지만, 일단 실행하면 avformat_find_stream_info 등의 함수를 실행하는 중에 read_packet 메서드가 콜백이 되어 다음과 같은 출력이 나옵니다.
ptr:1b27a880000 size:75337278
ptr:1b27a881000 size:75333182
ptr:1b27a88acff size:75292991
ptr:1b27a88bcff size:75288895
ptr:1b27a8907bb size:75269763
ptr:1b27a8917bb size:75265667
그리고 av_dump_format의 호출에 대한 출력은 예제의 특성과는 별 상관이 없습니다.
Input #0, matroska,webm, from 'D:\media_sample\test.mkv':
Metadata:
COMPATIBLE_BRANDS: iso6avc1mp41
MAJOR_BRAND : dash
MINOR_VERSION : 0
ENCODER : Lavf58.45.100
Duration: 00:03:07.98, start: -0.007000, bitrate: N/A
Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 1k tbn, 59.94 tbc (default)
Metadata:
HANDLER_NAME : ISO Media file produced by Google Inc.
DURATION : 00:03:07.954000000
Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
Metadata:
DURATION : 00:03:07.981000000
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
(
이 글의 소스 코드는 github에 올려져 있습니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]