-
-
Notifications
You must be signed in to change notification settings - Fork 315
/
Program.cs
161 lines (127 loc) · 6.83 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace FFmpeg.AutoGen.Example
{
internal class Program
{
private static unsafe void Main(string[] args)
{
Console.WriteLine(@"Current directory: " + Environment.CurrentDirectory);
Console.WriteLine(@"Runnung in {0}-bit mode.", Environment.Is64BitProcess ? @"64" : @"32");
// register path to ffmpeg
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
var ffmpegPath = $@"../../../../FFmpeg/bin/{(Environment.Is64BitProcess ? @"x64" : @"x86")}";
InteropHelper.RegisterLibrariesSearchPath(ffmpegPath);
break;
case PlatformID.Unix:
case PlatformID.MacOSX:
var libraryPath = Environment.GetEnvironmentVariable(InteropHelper.LD_LIBRARY_PATH);
InteropHelper.RegisterLibrariesSearchPath(libraryPath);
break;
}
ffmpeg.av_register_all();
ffmpeg.avcodec_register_all();
ffmpeg.avformat_network_init();
Console.WriteLine($"FFmpeg version info: {ffmpeg.av_version_info()}");
// setup logging
ffmpeg.av_log_set_level(ffmpeg.AV_LOG_VERBOSE);
av_log_set_callback_callback logCallback = (p0, level, format, vl) =>
{
if (level > ffmpeg.av_log_get_level()) return;
var lineSize = 1024;
var lineBuffer = stackalloc byte[lineSize];
var printPrefix = 1;
ffmpeg.av_log_format_line(p0, level, format, vl, lineBuffer, lineSize, &printPrefix);
var line = Marshal.PtrToStringAnsi((IntPtr) lineBuffer);
Console.Write(line);
};
ffmpeg.av_log_set_callback(logCallback);
// decode N frames from url or path
//string url = @"../../sample_mpeg4.mp4";
var url = @"http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4";
var pFormatContext = ffmpeg.avformat_alloc_context();
if (ffmpeg.avformat_open_input(&pFormatContext, url, null, null) != 0)
throw new ApplicationException(@"Could not open file");
if (ffmpeg.avformat_find_stream_info(pFormatContext, null) != 0)
throw new ApplicationException(@"Could not find stream info");
AVStream* pStream = null;
for (var i = 0; i < pFormatContext->nb_streams; i++)
if (pFormatContext->streams[i]->codec->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO)
{
pStream = pFormatContext->streams[i];
break;
}
if (pStream == null)
throw new ApplicationException(@"Could not found video stream");
var codecContext = *pStream->codec;
Console.WriteLine($"codec name: {ffmpeg.avcodec_get_name(codecContext.codec_id)}");
var width = codecContext.width;
var height = codecContext.height;
var sourcePixFmt = codecContext.pix_fmt;
var codecId = codecContext.codec_id;
var destinationPixFmt = AVPixelFormat.AV_PIX_FMT_BGR24;
var pConvertContext = ffmpeg.sws_getContext(width, height, sourcePixFmt,
width, height, destinationPixFmt,
ffmpeg.SWS_FAST_BILINEAR, null, null, null);
if (pConvertContext == null)
throw new ApplicationException(@"Could not initialize the conversion context");
var pConvertedFrame = ffmpeg.av_frame_alloc();
var convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixFmt, width, height, 1);
var convertedFrameBuffer = stackalloc byte[convertedFrameBufferSize];
var dstData = new byte_ptrArray4();
var dstLinesize = new int_array4();
ffmpeg.av_image_fill_arrays(ref dstData, ref dstLinesize, convertedFrameBuffer, destinationPixFmt, width, height, 1);
var pCodec = ffmpeg.avcodec_find_decoder(codecId);
if (pCodec == null)
throw new ApplicationException(@"Unsupported codec");
// reusing codec context from stream info, initally it was looking like this:
// AVCodecContext* pCodecContext = ffmpeg.avcodec_alloc_context3(pCodec); // but this is not working for all kind of codecs
var pCodecContext = &codecContext;
if ((pCodec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) == ffmpeg.AV_CODEC_CAP_TRUNCATED)
pCodecContext->flags |= ffmpeg.AV_CODEC_FLAG_TRUNCATED;
if (ffmpeg.avcodec_open2(pCodecContext, pCodec, null) < 0)
throw new ApplicationException(@"Could not open codec");
var pDecodedFrame = ffmpeg.av_frame_alloc();
var packet = new AVPacket();
var pPacket = &packet;
ffmpeg.av_init_packet(pPacket);
var frameNumber = 0;
while (frameNumber < 200)
{
try
{
if (ffmpeg.av_read_frame(pFormatContext, pPacket) < 0)
throw new ApplicationException(@"Could not read frame");
if (pPacket->stream_index != pStream->index)
continue;
if (ffmpeg.avcodec_send_packet(pCodecContext, pPacket) < 0)
throw new ApplicationException($@"Error while sending packet {frameNumber}");
if (ffmpeg.avcodec_receive_frame(pCodecContext, pDecodedFrame) < 0)
throw new ApplicationException($@"Error while receiving frame {frameNumber}");
Console.WriteLine($@"frame: {frameNumber}");
ffmpeg.sws_scale(pConvertContext, pDecodedFrame->data, pDecodedFrame->linesize, 0, height, dstData, dstLinesize);
}
finally
{
ffmpeg.av_packet_unref(pPacket);
ffmpeg.av_frame_unref(pDecodedFrame);
}
var convertedFrameBufferPtr = (IntPtr) convertedFrameBuffer;
using (var bitmap = new Bitmap(width, height, dstLinesize[0], PixelFormat.Format24bppRgb, convertedFrameBufferPtr))
bitmap.Save(@"frame.buffer.jpg", ImageFormat.Jpeg);
frameNumber++;
}
ffmpeg.av_free(pConvertedFrame);
ffmpeg.sws_freeContext(pConvertContext);
ffmpeg.av_free(pDecodedFrame);
ffmpeg.avcodec_close(pCodecContext);
ffmpeg.avformat_close_input(&pFormatContext);
}
}
}