1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
13 #ifndef _ASF_MOONLIGHT_H
14 #define _ASF_MOONLIGHT_H
21 typedef guint8 asf_byte
;
22 typedef guint16 asf_wchar
;
23 typedef guint16 asf_word
;
24 typedef guint32 asf_dword
;
25 typedef guint64 asf_qword
;
35 #define ASF_ERROR_VAL(fail, ...) { fprintf (stderr, __VA_ARGS__); return fail; }
36 #define ASF_ERROR(...) ASF_ERROR_VAL(false, __VA_ARGS__)
38 #define ASF_CHECK_VAL(condition, val, ...) if (condition) { ASF_ERROR_VAL (val, __VA_ARGS__); }
39 #define ASF_CHECK(condition, ...) if (condition) { ASF_ERROR (__VA_ARGS__); }
41 #define ASF_LOG(...)// printf (__VA_ARGS__)
43 #define ASF_LOG_ERROR(...) printf (__VA_ARGS__)
44 #define ASF_DUMP(...)// printf (__VA_ARGS__)
47 #include "asf-generated.h"
48 #include "asf-guids.h"
49 #include "asf-structures.h"
50 #include "asf-debug.h"
53 #include "pipeline-asf.h"
57 // according to http://msdn.microsoft.com/en-us/library/cc307965(VS.85).aspx the maximum size is 10 MB
58 #define ASF_OBJECT_MAX_SIZE (10 * 1024 * 1024)
66 class ASFPacket
: public EventObject
{
68 gint64 position
; // The position of this packet. -1 if not known.
69 int index
; // The index of this packet. -1 if not known.
70 IMediaSource
*source
; // The source which is to be used for reading into this packet.
74 virtual ~ASFPacket ();
77 ASFPacket (ASFParser
*parser
, IMediaSource
*source
);
79 asf_multiple_payloads
*payloads
; // The payloads in this packet
81 int GetPayloadCount (); // Returns the number of payloads in this packet.
82 asf_single_payload
*GetPayload (int index
/* 0 based */);
84 guint64
GetPts (int stream_id
/* 1 - 127 */); // Gets the pts of the first payload. 0 if no payloads.
85 asf_single_payload
*GetFirstPayload (int stream_id
/* 1 - 127 */); // Gets the index first payload of the specified stream.
87 IMediaSource
*GetSource () { return source
; }
88 void SetSource (IMediaSource
*source
);
94 ASFFrameReader
*readers
[128];
98 // The index of the next packet to be read.
99 guint64 next_packet_index
;
101 // Seeks to the specified pts directly on the source.
102 MediaResult
SeekToPts (guint64 pts
);
105 ASFReader (ASFParser
*parser
, ASFDemuxer
*demuxer
);
107 // Select the specified stream.
108 // No streams are selected by default.
109 void SelectStream (gint32 stream_index
, bool value
);
110 // Returns the frame reader for the specified stream.
111 // The stream must first have been selected using SelectStream.
112 ASFFrameReader
*GetFrameReader (gint32 stream_index
);
114 // Have we reached end of file?
117 // This method will seek to the first keyframe before the requested pts in all selected streams.
118 // Note that the streams will probably be positioned at different pts after a seek (given that
119 // for audio streams any frame is considered as a key frame, while for video there may be several
120 // seconds between every key frame).
121 MediaResult
Seek (guint64 pts
);
123 // Resets all readers
126 // Estimate the packet index of the specified pts.
127 // Calls EstimatePacketIndexOfPts on all readers and returns the lowest value.
128 guint64
EstimatePacketIndexOfPts (guint64 pts
);
130 // Reads another packet and stuffs the payloads into our queue.
131 // Called by the readers when they are out of data.
132 MediaResult
TryReadMore ();
135 bool CanSeek () { return true; }
137 guint64
GetLastAvailablePacketIndex ();
142 struct ASFFrameReaderData
{
143 asf_single_payload
*payload
;
144 ASFFrameReaderData
*prev
;
145 ASFFrameReaderData
*next
;
146 guint64 packet_index
;
148 ASFFrameReaderData (asf_single_payload
*load
)
155 ~ASFFrameReaderData ()
161 #define INVALID_START_PTS ((guint64) -1)
163 struct ASFFrameReaderIndex
{
168 * The data in an ASF file has the following structure:
172 * Chunks of Media objects
174 * The problem is that one chunk of "Media object data" can span several payloads (and packets),
175 * and the pieces may come unordered, like this:
177 * - first 25% of media object #1 for stream #1
178 * - first 25% of media object #1 for stream #2
179 * - first 25% of media object #1 for stream #3
180 * - middle 50% of media object #1 for stream #2
181 * - last 75% of media object #1 for stream #1
182 * => we have now all the data for the first media object of stream #1
184 * This class implements a reader that allows the consumer to just call Advance() and then get the all data
185 * for each "Media object" (here called "Frame", since it's shorter, and in general it corresponds
186 * to a frame of video/audio, etc, even though the ASF spec states that it can be just about anything)
187 * in one convenient Write () call.
189 * We keep reading payloads until we have all the data for a frame, the payloads currently not wanted are
190 * kept in a queue until the next Advance ().
193 class ASFFrameReader
{
196 IMediaStream
*stream
;
200 // The first pts that should be returned, any frames with pts below this one will be dropped.
203 // Only return key frames. Reset after we've returned a key frame.
204 bool key_frames_only
;
205 bool buffer_underflow
; // If the last time we tried to advance the buffer ran out of data
206 int stream_number
; // The stream this reader is reading for
209 // The queue of payloads we've built.
210 ASFFrameReaderData
*first
;
211 ASFFrameReaderData
*last
;
213 // A list of the payloads in the current frame
214 asf_single_payload
**payloads
;
217 // Information about the current frame.
222 guint32 index_size
; // The number of items in the index.
223 ASFFrameReaderIndex
*index
; // A table of ASFFrameReaderIndexes.
225 bool ResizeList (int size
); // Resizes the list of payloads to the requested size.
226 MediaResult
ReadMore (); // Reads another packet and stuffs the payloads into our queue
227 void RemoveAll (); // Deletes the entire queue of payloads (and deletes every element)
228 void Remove (ASFFrameReaderData
*data
); // Unlinks the payload from the queue and deletes it.
231 ASFFrameReader (ASFParser
*parser
, int stream_index
, ASFDemuxer
*demuxer
, ASFReader
*reader
, IMediaStream
*stream
);
234 // Advance to the next frame
235 MediaResult
Advance (bool read_if_needed
= true);
237 // Write the frame's data to a the destination
238 bool Write (void *dest
);
240 // Information about the current frame
241 guint64
Size () { return size
; }
242 bool IsKeyFrame () { return (payloads_size
> 0 && payloads
[0] != NULL
) ? payloads
[0]->is_key_frame
: false; }
243 guint64
Pts () { return pts
; }
244 int StreamId () { return stream_number
; }
246 void AppendPayload (asf_single_payload
*payload
, guint64 packet_index
);
248 // Index, returns the packet index of where the frame is.
249 // returns UINT32_MAX if not found in the index.
250 guint32
FrameSearch (guint64 pts
);
252 gint64
EstimatePtsPosition (guint64 pts
);
253 guint64
EstimatePacketIndexOfPts (guint64 pts
);
255 // Adds the current frame to the index.
256 void AddFrameIndex (guint64 packet_index
);
258 bool IsAudio (int stream
);
259 void SetOnlyKeyFrames (); // Sets the key_frames_only flag to true
260 void SetFirstPts (guint64
); // Sets the first pts which is to be returned.
263 IMediaStream
*GetStream () { return stream
; }
266 /* @IncludeInKinds */
267 class ASFParser
: public EventObject
{
269 ErrorEventArgs
*error
;
270 bool header_read_successfully
;
273 MediaResult
ReadData ();
274 asf_object
*ReadObject (asf_object
*guid
);
275 void SetStream (int stream_id
, const asf_stream_properties
*stream
);
276 void SetExtendedStream (int stream_id
, const asf_extended_stream_properties
*stream
);
278 IMediaSource
*source
; // The source used to read data.
281 virtual ~ASFParser ();
284 // The parser takes ownership of the source and will delete it when the parser is deleted.
285 ASFParser (IMediaSource
*source
, Media
*media
);
287 MediaResult
ReadHeader ();
289 // In any case (failure or success), the position of the source
290 // is set to the next packet.
291 MediaResult
ReadPacket (ASFPacket
**packet
);
293 // Seeks to the packet index (as long as the packet index >= 0), then reads it.
294 // If the packet index is < 0, then just read at the current position
295 MediaResult
ReadPacket (ASFPacket
**packet
, int packet_index
);
297 // Reads the number of the specified encoded length (0-3)
298 // encoded length 3 = read 4 bytes, rest equals encoded length and #bytes
299 // into the destionation.
300 static bool ReadEncoded (IMediaSource
*source
, guint32 encoded_length
, guint32
*dest
);
302 // Verifies that the requested size is a size that can be inside the header.
303 bool VerifyHeaderDataSize (guint32 size
);
305 // Allocates the requested memory (no size checking), reports
306 // an Out of Memory error if the memory can't be allocated, and returns
308 void *MallocVerified (guint32 size
);
310 // Allocates the requested memory and verifies that the size
311 // can actually be contained within the header. Reports an Out of Memory
312 // error if the memory can't be allocated, and returns NULL
313 void *Malloc (guint32 size
);
316 ErrorEventArgs
*GetLastError ();
317 const char *GetLastErrorStr ();
318 void AddError (char *msg
);
319 void AddError (const char *msg
);
320 void AddError (MediaResult code
, char *msg
);
321 void AddError (MediaResult code
, const char *msg
);
323 // Stream index: valid values range from 1 to 127
324 // If the stream_index doesn't specify a valid stream (for whatever reason), NULL is returned.
325 const asf_stream_properties
*GetStream (int stream_index
);
326 const asf_extended_stream_properties
*GetExtendedStream (int stream_index
);
328 // Checks if the stream_index (range 1 - 127) is a valid stream index in the asf file.
329 bool IsValidStream (int stream_index
);
331 // Returns the sequential stream index (range 1 - 127) from the specified stream index (range 1 - 127)
332 // Example: The file has streams #2, #5, #9, the sequential numbers would be 1, 2 and 3.
333 int GetSequentialStreamNumber (int stream_index
);
335 // Returns 0 on failure, otherwise the offset of the packet index.
336 gint64
GetPacketOffset (guint64 packet_index
);
338 // Returns the index of the packet at the specified offset (from the beginning of the file)
339 guint64
GetPacketIndex (gint64 offset
);
341 // Searches the header objects for the specified guid
342 // returns -1 if nothing is found.
343 int GetHeaderObjectIndex (const asf_guid
*guid
, int start
= 0);
345 // The number of packets in the stream (0 if unknown).
346 guint64
GetPacketCount ();
348 guint32
GetPacketSize ();
350 // The number of streams
351 int GetStreamCount ();
353 IMediaSource
*GetSource () { return source
; }
354 void SetSource (IMediaSource
*source
);
359 asf_header
*GetHeader ();
360 asf_object
*GetHeader (int index
);
361 asf_file_properties
*GetFileProperties ();
362 asf_object
*GetHeaderObject (const asf_guid
*guid
);
364 // This callback is called whenever a script command payload is encountered while decoding.
365 typedef void embedded_script_command_callback (void *state
, char *type
, char *text
, guint64 pts
);
366 embedded_script_command_callback
*embedded_script_command
;
367 void *embedded_script_command_state
;
369 // The following fields are available only after ReadHeader is called.
372 asf_object
**header_objects
;
373 asf_file_properties
*file_properties
;
374 asf_header_extension
*header_extension
;
375 const asf_stream_properties
*stream_properties
[127];
376 const asf_extended_stream_properties
*extended_stream_properties
[127];
378 asf_script_command
*script_command
;
381 gint64 data_offset
; // location of data object
382 gint64 packet_offset
; // location of the beginning of the first packet
383 gint64 packet_offset_end
; // location of the end of the last packet
387 #endif /* _ASF_MOONLIGHT_H */