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 |
using System;
namespace CASC.Camlann.Lancelot {
/// <summary>
/// Class for WMV Codec Private Data.
/// </summary>
public class VideoPrivateData {
/// <summary>
/// Size of the data, in bytes.
/// </summary>
/// <remarks>
/// I'm not sure if it's always 45 bytes, but don't tell anyone!
/// </remarks>
private const int Size = 45;
// these I found in the ASF specification (cf. section 9.2)
private uint EncodedImageWidth;
private uint EncodedImageHeight;
private byte ReservedFlags;
private ushort FormatDataSize;
// the BITMAPINFOHEADER structure [offset]
private uint biSize; // 0
private int biWidth; // 4
private int biHeight; // 8
private ushort biPlanes; // 12
private ushort biBitCount; // 14
private uint biCompression; // 16
private uint biSizeImage; // 20
private int biXPelsPerMeter; // 24
private int biYPelsPerMeter; // 28
private uint biClrUsed; // 32
private uint biClrImportant; // 36
private byte[] CodecSpecificData = null; // 40
/// <summary>
/// Image width.
/// </summary>
public int Width {
get {
return this.biWidth;
}
}
/// <summary>
/// Image height.
/// </summary>
public int Height {
get {
return this.biHeight;
}
}
/// <summary>
/// Creates VideoPrivateData from raw bytes.
/// </summary>
/// <param name="data">The data to be parsed.</param>
public VideoPrivateData( byte[] data ) {
// check buffer size
if ( data.Length != VideoPrivateData.Size ) {
throw new Exception( "Wrong buffer size." );
}
// read stuff
this.biSize = BitConverter.ToUInt32( data, 0 );
this.biWidth = BitConverter.ToInt32( data, 4 );
this.biHeight = BitConverter.ToInt32( data, 8 );
this.biPlanes = BitConverter.ToUInt16( data, 12 );
this.biBitCount = BitConverter.ToUInt16( data, 14 );
this.biCompression = BitConverter.ToUInt32( data, 16 );
this.biSizeImage = BitConverter.ToUInt32( data, 20 );
this.biXPelsPerMeter = BitConverter.ToInt32( data, 24 );
this.biYPelsPerMeter = BitConverter.ToInt32( data, 28 );
this.biClrUsed = BitConverter.ToUInt32( data, 32 );
this.biClrImportant = BitConverter.ToUInt32( data, 36 );
this.CodecSpecificData = new byte[data.Length - 40];
Array.Copy( data, 40, this.CodecSpecificData, 0, this.CodecSpecificData.Length );
// set some ASF stuff
this.ReservedFlags = 2; // this should always be 2
this.FormatDataSize = (ushort)data.Length;
// HACK: I have no idea why, but if I set those two
// to anything except 320x240, the whole thing just doesn't work.
this.EncodedImageWidth = 320;
this.EncodedImageHeight = 240;
return;
}
/// <summary>
/// Returns a base16-encoded (little-endian order) string containing the private data.
/// </summary>
/// <returns>A base16-encoded (little-endian order) string containing the private data.</returns>
public string ToBase16() {
string hex = "";
hex += Encoder.ToBase16( this.EncodedImageWidth );
hex += Encoder.ToBase16( this.EncodedImageHeight );
hex += Encoder.ToBase16( this.ReservedFlags );
hex += Encoder.ToBase16( this.FormatDataSize );
hex += Encoder.ToBase16( this.biSize );
hex += Encoder.ToBase16( this.biWidth );
hex += Encoder.ToBase16( this.biHeight );
hex += Encoder.ToBase16( this.biPlanes );
hex += Encoder.ToBase16( this.biBitCount );
hex += Encoder.ToBase16( this.biCompression );
hex += Encoder.ToBase16( this.biSizeImage );
hex += Encoder.ToBase16( this.biXPelsPerMeter );
hex += Encoder.ToBase16( this.biYPelsPerMeter );
hex += Encoder.ToBase16( this.biClrUsed );
hex += Encoder.ToBase16( this.biClrImportant );
// Now, if someone could tell me WHAT these bytes are,
// and in what order I should write them...
foreach ( byte b in this.CodecSpecificData ) {
hex += Encoder.ToBase16( b );
}
return hex;
}
}
} |