root/RetroCASC/CASC-Lancelot/Pages/RoomPage/Streaming/VideoPrivateData.cs

Author: moorglade Revision: 2 («Previous Next» Latest)
Date: 3 months ago (2009/10/20 20:11 UTC)
Show/hide line numbers
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;
		}
	}
}