2009-08-26 Chris Toshok <toshok@ximian.com>
[moon.git] / src / asf / asf.h
blob1b9e06f6e6df0c2a1c2dd9b5eb91b86c1c947727
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * asf.h:
5 * Contact:
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
16 #include <glib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <errno.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;
27 struct asf_guid;
28 struct asf_object;
30 class ASFParser;
31 class ASFFrameReader;
32 class ASFReader;
33 struct ASFContext;
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__)
42 //#define ASF_LOGGING
43 #define ASF_LOG_ERROR(...) printf (__VA_ARGS__)
44 #define ASF_DUMP(...)// printf (__VA_ARGS__)
45 //#define ASF_DUMPING
47 #include "asf-generated.h"
48 #include "asf-guids.h"
49 #include "asf-structures.h"
50 #include "asf-debug.h"
52 #include "pipeline.h"
53 #include "pipeline-asf.h"
54 #include "clock.h"
55 #include "error.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)
60 struct ASFContext {
61 ASFParser *parser;
62 IMediaSource *source;
65 /* @IncludeInKinds */
66 class ASFPacket : public EventObject {
67 private:
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.
71 ASFParser *parser;
73 protected:
74 virtual ~ASFPacket ();
76 public:
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);
89 MediaResult Read ();
92 class ASFReader {
93 private:
94 ASFFrameReader *readers [128];
95 ASFParser *parser;
96 IMediaSource *source;
97 ASFDemuxer *demuxer;
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);
104 public:
105 ASFReader (ASFParser *parser, ASFDemuxer *demuxer);
106 ~ASFReader ();
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?
115 bool Eof ();
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
124 void ResetAll ();
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 ();
134 // Can we seek?
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)
150 payload = load;
151 prev = NULL;
152 next = NULL;
155 ~ASFFrameReaderData ()
157 delete payload;
161 #define INVALID_START_PTS ((guint64) -1)
163 struct ASFFrameReaderIndex {
164 guint64 start_pts;
165 guint64 end_pts;
168 * The data in an ASF file has the following structure:
169 * Data
170 * Packets
171 * Payload(s)
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 {
194 private:
195 ASFDemuxer *demuxer;
196 IMediaStream *stream;
197 ASFParser *parser;
198 ASFReader *reader;
200 // The first pts that should be returned, any frames with pts below this one will be dropped.
201 guint64 first_pts;
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
207 bool positioned;
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;
215 int payloads_size;
217 // Information about the current frame.
218 guint64 size;
219 guint64 pts;
221 // Index data
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.
230 public:
231 ASFFrameReader (ASFParser *parser, int stream_index, ASFDemuxer *demuxer, ASFReader *reader, IMediaStream *stream);
232 ~ASFFrameReader ();
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);
257 bool IsAudio ();
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.
261 void Reset ();
263 IMediaStream *GetStream () { return stream; }
266 /* @IncludeInKinds */
267 class ASFParser : public EventObject {
268 private:
269 ErrorEventArgs *error;
270 bool header_read_successfully;
272 void Initialize ();
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);
277 Media *media;
278 IMediaSource *source; // The source used to read data.
280 protected:
281 virtual ~ASFParser ();
283 public:
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 ();
288 // Reads a packet
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
307 // NULL
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);
315 // Error handling
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);
356 // Field accessors
358 Media *GetMedia ();
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.
371 asf_header *header;
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];
377 asf_marker *marker;
378 asf_script_command *script_command;
380 asf_data *data;
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 */