-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMediaFile.cs
More file actions
156 lines (129 loc) · 4.37 KB
/
Copy pathMediaFile.cs
File metadata and controls
156 lines (129 loc) · 4.37 KB
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
using System;
using System.Collections.Generic;
using System.Text;
using FFmpegSharp.Interop;
using FFmpegSharp.Interop.Format;
using System.IO;
using FFmpegSharp.Interop.Codec;
using System.Collections.ObjectModel;
namespace FFmpegSharp
{
public unsafe class MediaFile : IDisposable
{
internal AVFormatContext FormatContext;
private bool m_disposed = false;
private SortedList<int, DecoderStream> m_streams;
private string m_filename;
#region Properties
public unsafe ReadOnlyCollection<DecoderStream> Streams
{
get { return new ReadOnlyCollection<DecoderStream>(m_streams.Values); }
}
public string Filename
{
get { return m_filename; }
}
public long Length
{
get { return FormatContext.file_size; }
}
public string FileFormat
{
get { unsafe { return FormatContext.iformat->name; } }
}
/// <summary>
/// Duration of the stream
/// </summary>
public TimeSpan Duration
{
get { return new TimeSpan((long)(RawDuration * 1e7)); }
}
public double RawDuration
{
get
{
double duration = (double)(FormatContext.duration / (double)FFmpeg.AV_TIME_BASE);
if (duration < 0)
duration = 0;
return duration;
}
}
#endregion
static MediaFile()
{
// Register all codecs and protocols
FFmpeg.av_register_all();
#if DEBUG
FFmpeg.av_log_set_level(1000);
#endif
}
public MediaFile(FileInfo File) : this(File.FullName) { }
public MediaFile(FileStream File, CodecType codecType) : this(File.Name) { }
public unsafe MediaFile(string Filename)
{
if (String.IsNullOrEmpty(Filename))
throw new ArgumentNullException("Filename");
m_filename = Filename;
// Open the file with FFmpeg
if (FFmpeg.av_open_input_file(out FormatContext, Filename) != AVError.OK)
throw new DecoderException("Couldn't open file");
if (FFmpeg.av_find_stream_info(ref FormatContext) < AVError.OK)
throw new DecoderException("Couldn't find stream info");
if (FormatContext.nb_streams < 1)
throw new DecoderException("No streams found");
m_streams = new SortedList<int, DecoderStream>();
for (int i = 0; i < FormatContext.nb_streams; i++)
{
AVStream stream = *FormatContext.streams[i];
switch (stream.codec->codec_type)
{
case CodecType.CODEC_TYPE_VIDEO:
m_streams.Add(i, new VideoDecoderStream(this, ref stream));
break;
case CodecType.CODEC_TYPE_AUDIO:
m_streams.Add(i, new AudioDecoderStream(this, ref stream));
break;
case CodecType.CODEC_TYPE_UNKNOWN:
case CodecType.CODEC_TYPE_DATA:
case CodecType.CODEC_TYPE_SUBTITLE:
default:
m_streams.Add(i, null);
break;
}
}
}
internal void EnqueueNextPacket()
{
AVPacket packet = new AVPacket();
FFmpeg.av_init_packet(ref packet);
if (FFmpeg.av_read_frame(ref FormatContext, ref packet) < 0)
throw new System.IO.EndOfStreamException();
DecoderStream dest = null;
if (m_streams.TryGetValue(packet.stream_index, out dest))
dest.PacketQueue.Enqueue(packet);
else
FFmpeg.av_free_packet(ref packet);
}
~MediaFile()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!m_disposed)
{
m_disposed = true;
if (disposing)
{
m_streams = null;
}
FFmpeg.av_close_input_file(ref FormatContext);
}
}
}
}