2009-06-17 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / asf / asf.cpp
blob38eba55f3071349b3ae9dd9e0117a2282e137041
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * asf.cpp:
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 #ifdef HAVE_CONFIG_H
14 #include <config.h>
15 #endif
17 #include "asf.h"
18 #include "debug.h"
19 #include "clock.h"
20 #include "mediaelement.h"
23 ASFParser
26 ASFParser::ASFParser (IMediaSource *source, Media *media)
27 : EventObject (Type::ASFPARSER)
29 LOG_ASF ("ASFParser::ASFParser ('%p'), this: %p.\n", source, this);
30 this->media = NULL;
31 this->source = NULL;
33 g_return_if_fail (media != NULL);
34 g_return_if_fail (source != NULL);
36 this->source = source;
37 this->source->ref ();
38 this->media = media;
40 Initialize ();
43 guint64
44 ASFParser::GetPacketCount ()
46 return file_properties->data_packet_count;
49 Media*
50 ASFParser::GetMedia ()
52 return media;
55 int
56 ASFParser::GetSequentialStreamNumber (int stream_index)
58 int result = 0;
59 for (int i = 1; i <= stream_index; i++) {
60 if (IsValidStream (i))
61 result++;
63 return result;
66 int
67 ASFParser::GetStreamCount ()
69 int result = 0;
70 for (int i = 1; i <= 127; i++) {
71 if (IsValidStream (i))
72 result++;
74 return result;
77 void
78 ASFParser::Initialize ()
80 LOG_ASF ("ASFParser::Initialize ()\n");
81 header = NULL;
82 data = NULL;
83 data_offset = 0;
84 packet_offset = 0;
85 packet_offset_end = 0;
86 header_objects = NULL;
87 header_extension = NULL;
88 script_command = NULL;
89 marker = NULL;
90 file_properties = NULL;
91 error = NULL;
92 header_read_successfully = false;
93 embedded_script_command = NULL;
94 embedded_script_command_state = NULL;
95 memset (stream_properties, 0, sizeof (asf_stream_properties *) * 127);
96 memset (extended_stream_properties, 0, sizeof (asf_extended_stream_properties *) * 127);
99 ASFParser::~ASFParser ()
101 LOG_ASF ("ASFParser::~ASFParser ().\n");
103 if (source)
104 source->unref ();
105 if (error)
106 error->unref ();
107 g_free (header);
108 g_free (data);
110 if (header_objects) {
111 for (int i = 0; header_objects[i]; i++)
112 g_free (header_objects[i]);
114 g_free (header_objects);
118 bool
119 ASFParser::ReadEncoded (IMediaSource *source, guint32 length, guint32 *dest)
121 guint16 result2 = 0;
122 guint8 result1 = 0;
124 switch (length) {
125 case 0x00:
126 return true;
127 case 0x01:
128 if (!source->ReadAll (&result1, 1))
129 return false;
130 *dest = result1;
131 return true;
132 case 0x02:
133 if (!source->ReadAll (&result2, 2))
134 return false;
135 *dest = result2;
136 return true;
137 case 0x03:
138 return source->ReadAll (dest, 4);
139 default:
140 //TODO: parser->AddError (g_strdup_printf ("Invalid read length: %i.", length));
141 return false;
145 bool
146 ASFParser::VerifyHeaderDataSize (guint32 size)
148 if (header == NULL)
149 return false;
151 return size >= 0 && size < header->size;
154 void *
155 ASFParser::MallocVerified (guint32 size)
157 void *result = g_try_malloc0 (size);
159 if (result == NULL)
160 AddError ("Out of memory.");
162 return result;
165 void *
166 ASFParser::Malloc (guint32 size)
168 if (!VerifyHeaderDataSize (size))
169 return NULL;
171 return MallocVerified (size);
174 asf_object *
175 ASFParser::ReadObject (asf_object *obj)
177 ASFTypes type = asf_get_guid_type (&obj->id);
178 asf_object *result = NULL;
179 char *guid;
181 LOG_ASF ("ASFParser::ReadObject ('%s', %" G_GUINT64_FORMAT ")\n", asf_guid_tostring (&obj->id), obj->size);
183 if (obj->size < sizeof (asf_object) || obj->size > ASF_OBJECT_MAX_SIZE) {
184 AddError (g_strdup_printf ("Header corrupted (invalid size: %" G_GUINT64_FORMAT ")", obj->size));
185 return NULL;
188 if (type == ASF_NONE) {
189 guid = asf_guid_tostring (&obj->id);
190 AddError (g_strdup_printf ("Unrecognized guid: %s.", guid));
191 g_free (guid);
192 return NULL;
195 result = (asf_object *) Malloc (obj->size);
196 if (result == NULL) {
197 guid = asf_guid_tostring (&obj->id);
198 AddError (g_strdup_printf ("Header corrupted (id: %s)", guid));
199 g_free (guid);
200 return NULL;
203 memcpy (result, obj, sizeof (asf_object));
205 if (obj->size > sizeof (asf_object)) {
206 if (!source->ReadAll (((char *) result) + sizeof (asf_object), obj->size - sizeof (asf_object))) {
207 g_free (result);
208 return NULL;
212 if (!asf_object_validate_exact (result, this)) {
213 g_free (result);
214 return NULL;
217 return result;
220 MediaResult
221 ASFParser::ReadPacket (ASFPacket **packet, int packet_index)
223 bool eof = false;
225 LOG_ASF ("ASFParser::ReadPacket (%s, %d) at %" G_GUINT64_FORMAT ".\n", packet ? "non-null" : "null", packet_index, GetPacketOffset (packet_index));
227 if (packet_index >= 0) {
228 gint64 packet_count = GetPacketCount ();
229 if (packet_count > 0 && packet_count < packet_index + 1)
230 return MEDIA_NO_MORE_DATA;
232 gint64 position = GetPacketOffset (packet_index);
234 if (!source->IsPositionAvailable (position + GetPacketSize (), &eof))
235 return eof ? MEDIA_NO_MORE_DATA : MEDIA_NOT_ENOUGH_DATA;
237 LOG_ASF ("ASFParser::ReadPacket (%p, %i): determined that position %lld + size %i = %lld is available.\n",
238 packet, packet_index, position, GetPacketSize (), position + GetPacketSize ());
239 if (position == 0 || (source->GetPosition () != position))
240 source->Seek (position, SEEK_SET);
243 return ASFParser::ReadPacket (packet);
246 MediaResult
247 ASFParser::ReadPacket (ASFPacket **packet)
249 MediaResult result;
250 MmsPlaylistEntry *mqs;
251 gint64 initial_position;
252 gint64 next_pos;
253 gint64 pi;
255 *packet = NULL;
257 if (source->GetType () == MediaSourceTypeMmsEntry) {
258 mqs = (MmsPlaylistEntry *) source;
259 *packet = mqs->Pop ();
261 if (*packet == NULL) {
262 LOG_ASF ("ASFParser::ReadPacket (%p): no more data in queue source (finished: %i).\n", packet, mqs->IsFinished ());
263 return mqs->IsFinished () ? MEDIA_NO_MORE_DATA : MEDIA_BUFFER_UNDERFLOW;
266 return MEDIA_SUCCESS;
269 initial_position = source->GetPosition ();
270 pi = GetPacketIndex (initial_position);
271 next_pos = GetPacketOffset (1 + pi);
273 LOG_ASF ("ASFParser::ReadPacket (%s): Reading packet at %lld (index: %lld) of %lld packets.\n",
274 packet ? "non-null" : "null", initial_position, pi, data->data_packet_count);
277 *packet = new ASFPacket (this, source);
279 result = (*packet)->Read ();
280 if (!MEDIA_SUCCEEDED (result)) {
281 source->Seek (next_pos, SEEK_SET);
282 return result;
285 /* If we are "positioned", need to seek to the start of the next packet */
287 if (source->GetType () != MediaSourceTypeMemory)
288 source->Seek (next_pos, SEEK_SET);
290 return result;
293 MediaResult
294 ASFParser::ReadData ()
296 LOG_ASF ("ASFParser::ReadData ().\n");
298 if (this->data != NULL) {
299 AddError ("ReadData has already been called.");
300 return MEDIA_FAIL;
303 #if DEBUG
304 // We should already be positioned at where the data is
305 if (source->CanSeek () && source->GetPosition () != (gint64) header->size) {
306 fprintf (stderr, "Moonlight assert failure, asf source isn't positioned correctly.\n");
308 #endif
310 data = (asf_data *) Malloc (sizeof (asf_data));
311 if (data == NULL) {
312 AddError ("Data corruption in data.");
313 return MEDIA_FAIL;
316 if (!source->ReadAll (data, sizeof (asf_data))) {
317 g_free (data);
318 data = NULL;
319 return MEDIA_FAIL;
322 asf_object_dump_exact (data);
324 LOG_ASF ("Data %p has %lld packets.\n", data, data->data_packet_count);
326 this->data = data;
328 return MEDIA_SUCCESS;
331 MediaResult
332 ASFParser::ReadHeader ()
334 bool eof = false;
336 LOG_ASF ("ASFParser::ReadHeader (), header_read_successfully: %i\n", header_read_successfully);
338 if (header_read_successfully)
339 return MEDIA_SUCCESS;
341 header = (asf_header *) MallocVerified (sizeof (asf_header));
342 if (header == NULL) {
343 LOG_ASF ("ASFParser::ReadHeader (): Malloc failed.\n");
344 return MEDIA_FAIL;
347 if (!source->IsPositionAvailable (sizeof (asf_header), &eof)) {
348 LOG_ASF ("ASFParser::ReadHeader (): Not enough data, eof: %i, requested pos: %i, actual available pos: %i\n", eof, (int) sizeof (asf_header), (int) source->GetLastAvailablePosition ());
349 return eof ? MEDIA_FAIL : MEDIA_NOT_ENOUGH_DATA;
352 if (!source->Peek (header, sizeof (asf_header))) {
353 LOG_ASF ("ASFParser::ReadHeader (): source->Read () failed.\n");
354 return MEDIA_FAIL;
357 asf_header_dump (header);
359 // We are not allowed to leave the stream with a position > 0 if we return MEDIA_NOT_ENOUGH_DATA,
360 // so check if there is enough data to read both the header object and the data object header here,
361 // which is what we need to read in order to return true from this method. This way we avoid peeking
362 // after this point, we just read ahead.
363 if (!source->IsPositionAvailable (header->size + sizeof (asf_data), &eof)) {
364 LOG_ASF ("ASFParser::ReadHeader (): Not enough data, eof: %i, requested pos: %i, actual available pos: %i\n", eof, (int) (header->size + sizeof (asf_data)), (int) source->GetLastAvailablePosition ());
365 return eof ? MEDIA_FAIL : MEDIA_NOT_ENOUGH_DATA;
368 if (!asf_header_validate (header, this)) {
369 LOG_ASF ("Header validation failed, error: '%s'\n", GetLastErrorStr ());
370 return MEDIA_FAIL;
373 header_objects = (asf_object **) Malloc ((header->object_count + 1) * sizeof (asf_object*));
374 if (header_objects == NULL) {
375 AddError ("Data corruption in header.");
376 return MEDIA_FAIL;
379 LOG_ASF ("ASFParser::ReadHeader (): about to read streams...\n");
380 if (!source->ReadAll (header, sizeof (asf_header))) {
381 // We just peeked the header above, read it for real.
382 LOG_ASF ("ASFParser::ReadHeader (): re-reading header failed.\n");
383 return MEDIA_FAIL;
386 bool any_streams = false;
387 for (guint32 i = 0; i < header->object_count; i++) {
388 asf_object tmp;
390 if (!source->ReadAll (&tmp, sizeof (asf_object)))
391 return MEDIA_FAIL;
393 if (!(header_objects [i] = ReadObject (&tmp)))
394 return MEDIA_FAIL;
396 if (asf_guid_compare (&asf_guids_stream_properties, &header_objects[i]->id)) {
397 asf_stream_properties *stream = (asf_stream_properties *) header_objects[i];
398 SetStream (stream->get_stream_id (), stream);
399 any_streams = true;
402 if (asf_guid_compare (&asf_guids_file_properties, &header_objects [i]->id)) {
403 if (file_properties != NULL) {
404 AddError ("Multiple file property object in the asf data.");
405 return MEDIA_FAIL;
407 file_properties = (asf_file_properties*) header_objects [i];
410 if (asf_guid_compare (&asf_guids_header_extension, &header_objects [i]->id)) {
411 if (header_extension != NULL) {
412 AddError ("Multiple header extension objects in the asf data.");
413 return MEDIA_FAIL;
415 header_extension = (asf_header_extension*) header_objects [i];
418 if (asf_guid_compare (&asf_guids_marker, &header_objects [i]->id)) {
419 if (marker != NULL) {
420 AddError ("Multiple marker objects in the asf data.");
421 return MEDIA_FAIL;
423 marker = (asf_marker*) header_objects [i];
426 if (asf_guid_compare (&asf_guids_script_command, &header_objects [i]->id)) {
427 if (script_command != NULL) {
428 AddError ("Multiple script command objects in the asf data.");
429 return MEDIA_FAIL;
431 script_command = (asf_script_command*) header_objects [i];
434 asf_object_dump_exact (header_objects [i]);
437 // Check if there are stream properties in any extended stream properties object.
438 if (header_extension != NULL) {
439 asf_object **objects = header_extension->get_objects ();
440 for (int i = 0; objects != NULL && objects [i] != NULL; i++) {
441 if (asf_guid_compare (&asf_guids_extended_stream_properties, &objects [i]->id)) {
442 asf_extended_stream_properties *aesp = (asf_extended_stream_properties *) objects [i];
443 SetExtendedStream (aesp->stream_id, aesp);
444 const asf_stream_properties *stream = aesp->get_stream_properties ();
445 if (stream != NULL) {
446 if (stream->get_stream_id () != aesp->stream_id) {
447 g_free (objects);
448 AddError ("There is an invalid extended stream properties object (it contains a stream properties object whose stream id doesn't match the stream id of the extended stream properties object).");
449 return MEDIA_FAIL;
450 } else {
451 SetStream (stream->get_stream_id (), stream);
453 } else if (!IsValidStream (aesp->stream_id)) {
454 g_free (objects);
455 AddError ("There is an extended stream properties object that doesn't have a corresponding strem properties object.");
456 return MEDIA_FAIL;
458 any_streams = true;
461 g_free (objects);
464 // Check for required objects.
466 if (file_properties == NULL) {
467 AddError ("No file property object in the asf data.");
468 return MEDIA_FAIL;
471 if (header_extension == NULL) {
472 AddError ("No header extension object in the asf data.");
473 return MEDIA_FAIL;
476 if (!any_streams) {
477 AddError ("No streams in the asf data.");
478 return MEDIA_FAIL;
481 data_offset = header->size;
482 packet_offset = data_offset + sizeof (asf_data);
483 if (file_properties->data_packet_count != 0)
484 packet_offset_end = packet_offset + file_properties->data_packet_count * file_properties->min_packet_size;
485 else
486 packet_offset_end = -1;
488 LOG_ASF ("ASFParser::ReadHeader (): Header read successfully, position: %lld, header size: %lld\n", source->GetPosition (), header->size);
490 if (!MEDIA_SUCCEEDED (ReadData ()))
491 return MEDIA_FAIL;
493 LOG_ASF ("ASFParser::ReadHeader (): Header read successfully [2].\n");
495 header_read_successfully = true;
497 return MEDIA_SUCCESS;
500 void
501 ASFParser::SetSource (IMediaSource *source)
503 if (this->source)
504 this->source->unref ();
505 this->source = source;
506 if (this->source)
507 this->source->ref ();
510 ErrorEventArgs *
511 ASFParser::GetLastError ()
513 return error;
516 const char *
517 ASFParser::GetLastErrorStr ()
519 return error ? error->error_message : "";
522 void
523 ASFParser::AddError (const char *msg)
525 AddError (MEDIA_CORRUPTED_MEDIA, msg);
528 void
529 ASFParser::AddError (char *msg)
531 AddError (MEDIA_CORRUPTED_MEDIA, msg);
534 void
535 ASFParser::AddError (MediaResult code, const char *msg)
537 AddError (code, g_strdup (msg));
540 void
541 ASFParser::AddError (MediaResult code, char *msg)
543 fprintf (stdout, "ASF error: %s.\n", msg);
545 if (error == NULL && media)
546 media->ReportErrorOccurred (new ErrorEventArgs (MediaError, 4001, msg));
548 g_free (msg);
551 const asf_stream_properties*
552 ASFParser::GetStream (int stream_index)
554 if (stream_index < 1 || stream_index > 127)
555 return NULL;
557 return stream_properties [stream_index - 1];
560 const asf_extended_stream_properties*
561 ASFParser::GetExtendedStream (int stream_index)
563 if (stream_index < 1 || stream_index > 127)
564 return NULL;
566 return extended_stream_properties [stream_index - 1];
569 void
570 ASFParser::SetStream (int stream_index, const asf_stream_properties *stream)
572 if (stream_index < 1 || stream_index > 127) {
573 printf ("ASFParser::SetStream (%i, %p): Invalid stream index.\n", stream_index, stream);
574 return;
577 stream_properties [stream_index - 1] = stream;
580 void
581 ASFParser::SetExtendedStream (int stream_index, const asf_extended_stream_properties *stream)
583 if (stream_index < 1 || stream_index > 127) {
584 printf ("ASFParser::SetExtendedStream (%i, %p): Invalid stream index.\n", stream_index, stream);
585 return;
588 extended_stream_properties [stream_index - 1] = stream;
591 bool
592 ASFParser::IsValidStream (int stream_index)
594 return GetStream (stream_index) != NULL;
597 gint64
598 ASFParser::GetPacketOffset (guint64 packet_index)
600 if (packet_index < 0 || (file_properties->data_packet_count > 0 && packet_index >= file_properties->data_packet_count)) {
601 // AddError (g_strdup_printf ("ASFParser::GetPacketOffset (%i): Invalid packet index (there are %" G_GUINT64_FORMAT " packets).", packet_index, file_properties->data_packet_count));
602 return 0;
605 // CHECK: what if min_packet_size != max_packet_size?
606 return packet_offset + packet_index * file_properties->min_packet_size;
609 guint32
610 ASFParser::GetPacketSize ()
612 return file_properties->min_packet_size;
615 guint64
616 ASFParser::GetPacketIndex (gint64 offset)
618 if (offset < packet_offset)
619 return 0;
621 if (packet_offset_end > 0 && offset > packet_offset_end)
622 return file_properties->data_packet_count - 1;
624 return (offset - packet_offset) / file_properties->min_packet_size;
627 asf_header *
628 ASFParser::GetHeader ()
630 return header;
633 asf_file_properties *
634 ASFParser::GetFileProperties ()
636 return file_properties;
639 asf_object *
640 ASFParser::GetHeaderObject (const asf_guid *guid)
642 int index = GetHeaderObjectIndex (guid);
644 if (index >= 0) {
645 return header_objects [index];
646 } else {
647 return NULL;
651 int
652 ASFParser::GetHeaderObjectIndex (const asf_guid *guid, int start)
654 int i = start;
656 if (i < 0)
657 return -1;
659 while (header_objects [i] != NULL) {
660 if (asf_guid_compare (guid, &header_objects [i]->id))
661 return i;
663 i++;
666 return -1;
669 asf_object *
670 ASFParser::GetHeader (int index)
672 if (index < 0)
673 return NULL;
675 return header_objects [index];
679 ASFPacket
682 ASFPacket::ASFPacket (ASFParser *parser, IMediaSource *source)
683 : EventObject (Type::ASFPACKET)
685 payloads = NULL;
686 position = -1;
687 index = -1;
688 this->source = source;
689 if (this->source)
690 this->source->ref ();
691 this->parser = parser;
692 if (this->parser)
693 this->parser->ref ();
696 ASFPacket::~ASFPacket ()
698 delete payloads;
699 if (this->source)
700 this->source->unref ();
701 if (this->parser)
702 this->parser->unref ();
705 void
706 ASFPacket::SetSource (IMediaSource *source)
708 if (this->source != NULL)
709 this->source->unref ();
710 this->source = source;
711 if (this->source != NULL)
712 this->source->ref ();
716 ASFPacket::GetPayloadCount ()
718 if (!payloads)
719 return 0;
721 return payloads->get_number_of_payloads ();
724 asf_single_payload *
725 ASFPacket::GetPayload (int index /* 0 based */)
727 if (index >= 0 && index < GetPayloadCount ())
728 return payloads->payloads [index];
730 return NULL;
733 guint64
734 ASFPacket::GetPts (int stream_id)
736 asf_single_payload *first;
738 if (!payloads)
739 return 0;
741 if (!(first = GetFirstPayload (stream_id)))
742 return 0;
744 return first->get_presentation_time ();
747 asf_single_payload *
748 ASFPacket::GetFirstPayload (int stream_id /* 1 - 127 */)
750 if (!payloads)
751 return NULL;
753 int index = 0;
754 while (payloads->payloads [index] != NULL) {
755 if (payloads->payloads [index]->stream_id == stream_id)
756 return payloads->payloads [index];
757 index++;
760 return NULL;
763 MediaResult
764 ASFPacket::Read ()
766 MediaResult result;
767 asf_payload_parsing_information ppi;
768 asf_error_correction_data ecd;
769 ASFContext context;
771 LOG_ASF ("ASFPacket::Read (): source: %s, source position: %lld\n", source->ToString (), source->GetPosition ());
773 context.parser = parser;
774 context.source = this->source;
776 result = ecd.FillInAll (&context);
777 if (!MEDIA_SUCCEEDED (result))
778 return result;
780 asf_error_correction_data_dump (&ecd);
782 result = ppi.FillInAll (&context);
783 if (!MEDIA_SUCCEEDED (result)) {
784 ASF_LOG_ERROR ("ASFPacket::Read (): FillIn payload parsing information failed.\n");
785 return result;
788 asf_payload_parsing_information_dump (&ppi);
790 asf_multiple_payloads *mp = new asf_multiple_payloads ();
791 result = mp->FillInAll (&context, &ecd, ppi);
792 if (!MEDIA_SUCCEEDED (result)) {
793 ASF_LOG_ERROR ("ASFPacket::Read (): FillIn multiple payloads failed, current position: %lld, in stream %s\n", source->GetPosition (), source->ToString ());
794 delete mp;
795 return result;
798 payloads = mp;
800 return MEDIA_SUCCESS;
804 * ASFReader
807 ASFReader::ASFReader (ASFParser *parser, ASFDemuxer *demuxer)
809 this->parser = parser;
810 this->demuxer = demuxer;
811 this->source = demuxer->GetSource ();
812 next_packet_index = 0;
813 memset (readers, 0, sizeof (ASFFrameReader*) * 128);
816 ASFReader::~ASFReader ()
818 for (int i = 0; i < 128; i++)
819 delete readers [i];
822 void
823 ASFReader::SelectStream (gint32 stream_index, bool value)
825 LOG_ASF ("ASFReader::SelectStream (%i, %i)\n", stream_index, value);
827 if (stream_index <= 0 || stream_index >= 128) {
828 fprintf (stderr, "ASFReader::SelectStream (%i, %i): Invalid stream index\n", stream_index, value);
829 return;
832 if (value) {
833 if (readers [stream_index] == NULL) {
834 readers [stream_index] = new ASFFrameReader (parser, stream_index, demuxer, this, demuxer->GetStreamOfASFIndex (stream_index));
836 } else {
837 if (readers [stream_index] != NULL) {
838 delete readers [stream_index];
839 readers [stream_index] = NULL;
844 ASFFrameReader *
845 ASFReader::GetFrameReader (gint32 stream_index)
847 if (stream_index <= 0 || stream_index >= 128) {
848 fprintf (stderr, "ASFReader::GetFrameReader (%i): Invalid stream index.\n", stream_index);
849 return NULL;
852 return readers [stream_index];
855 MediaResult
856 ASFReader::TryReadMore ()
858 LOG_ASF ("ASFReader::TryReadMore (), source: %s, next_packet_index: %i\n", source->ToString (), (int) next_packet_index);
860 int payloads_added = 0;
861 guint64 current_packet_index;
862 gint64 position, last_available_position;
863 MediaResult read_result = MEDIA_FAIL;
864 ASFPacket* packet = NULL;
866 g_return_val_if_fail (parser != NULL, MEDIA_FAIL);
867 g_return_val_if_fail (parser->GetMedia () != NULL, MEDIA_FAIL);
869 #if SANITY
870 if (!parser->GetMedia ()->InMediaThread ())
871 printf ("ASFReader::TryReadMore (): This method should only be called on the media thread (media id: %i).\n", GET_OBJ_ID (parser->GetMedia ()));
872 #endif
874 do {
875 if (Eof ()) {
876 LOG_ASF ("ASFReader::ReadMore (): eof\n");
877 return MEDIA_NO_MORE_DATA;
880 LOG_ASF ("ASFReader::TryReadMore (), current_packet_index: %lld, next_packet_index: %lld\n", current_packet_index, next_packet_index);
882 if (source->GetType () == MediaSourceTypeMmsEntry) {
883 read_result = parser->ReadPacket (&packet);
884 } else if (source->CanSeek ()) {
885 position = source->GetPosition ();
886 last_available_position = source->GetLastAvailablePosition ();
887 if (last_available_position != -1 && position + parser->GetPacketSize () > last_available_position) {
888 LOG_ASF ("ASFReader::TryReadMore (), position: %lld, last_available_position: %lld, packet size: %i\n", position, last_available_position, parser->GetPacketSize ());
889 return MEDIA_BUFFER_UNDERFLOW;
891 LOG_ASF ("ASFReader::TryReadMore (), position: %lld, last_available_position: %lld, packet size: %i, current packet index: %lld [READING]\n", position, last_available_position, parser->GetPacketSize (), next_packet_index);
893 read_result = parser->ReadPacket (&packet, next_packet_index);
894 } else {
895 // We should either be seekable, or be MediaSourceTypeMmsEntry.
896 fprintf (stderr, "Moonlight: Media assert failure (source should be either MmsSource or seekable). Media playback errors will probably occur.\n");
897 return MEDIA_FAIL;
900 if (read_result == MEDIA_NOT_ENOUGH_DATA) {
901 LOG_ASF ("ASFReader::ReadMore (): Not enough data.\n");
902 if (packet)
903 packet->unref ();
904 return read_result;
907 current_packet_index = next_packet_index;
908 next_packet_index++;
910 LOG_ASF ("ASFReader::ReadMore (): current packet index: %" G_GUINT64_FORMAT ", position: %lld, calculated packet index: %llu\n",
911 current_packet_index, source->GetPosition (), parser->GetPacketIndex (source->GetPosition ()));
913 if (read_result == MEDIA_INVALID_DATA) {
914 LOG_ASF ("ASFReader::ReadMore (): Skipping invalid packet (index: %" G_GUINT64_FORMAT ")\n", current_packet_index);
915 if (packet)
916 packet->unref ();
917 continue;
920 if (!MEDIA_SUCCEEDED (read_result)) {
921 LOG_ASF ("ASFReader::ReadMore (): could not read more packets (error: %i)\n", (int) read_result);
922 if (packet)
923 packet->unref ();
924 return read_result;
927 // Distribute the payloads to the per-stream readers.
928 asf_single_payload** payloads = packet->payloads->steal_payloads ();
929 ASFFrameReader *reader;
930 int i = -1;
931 int stream_id;
933 while (payloads [++i] != NULL) {
934 stream_id = payloads [i]->stream_id;
935 reader = GetFrameReader (stream_id);
936 if (reader == NULL) {
937 LOG_ASF ("ASFReader::ReadMore (): skipped, stream: %i, added pts: %" G_GUINT64_FORMAT "\n", payloads [i]->stream_id, (guint64) payloads [i]->get_presentation_time ());
938 delete payloads [i];
939 continue;
942 LOG_ASF ("ASFReader::ReadMore (): delivered payload for stream %i with pts %" G_GUINT64_FORMAT "\n", payloads [i]->stream_id, (guint64) payloads [i]->get_presentation_time () - 5000);
943 reader->AppendPayload (payloads [i], current_packet_index);
944 payloads_added++;
946 g_free (payloads);
948 LOG_ASF ("ASFReader::ReadMore (): read %d payloads.\n", payloads_added);
950 packet->unref ();
951 } while (payloads_added == 0);
953 return MEDIA_SUCCESS;
956 bool
957 ASFReader::Eof ()
959 guint64 packet_count = parser->GetPacketCount ();
961 if (packet_count == 0)
962 return false;
964 if (source->GetType () == MediaSourceTypeMms || source->GetType () == MediaSourceTypeMmsEntry)
965 return source->Eof ();
967 if (source->GetSize () <= 0)
968 return false;
970 return (source->GetPosition() >= source->GetSize () ||
971 next_packet_index >= packet_count);
975 void
976 ASFReader::ResetAll ()
978 for (int i = 0; i < 128; i++) {
979 if (readers [i] != NULL)
980 readers [i]->Reset ();
984 guint64
985 ASFReader::EstimatePacketIndexOfPts (guint64 pts)
987 guint64 result = G_MAXUINT64;
988 for (int i = 0; i < 128; i++) {
989 if (readers [i] == NULL)
990 continue;
992 result = MIN (readers [i]->EstimatePacketIndexOfPts (pts), result);
994 return result == G_MAXUINT64 ? 0 : result;
997 MediaResult
998 ASFReader::SeekToPts (guint64 pts)
1000 ResetAll ();
1002 return source->SeekToPts (pts);
1005 MediaResult
1006 ASFReader::Seek (guint64 pts)
1008 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "), CanSeek: %i, CanSeekToPts(): %i\n", pts, CanSeek (), source->CanSeekToPts ());
1010 #if SANITY
1011 if (!parser->GetMedia ()->InMediaThread ())
1012 printf ("ASFReader::TryReadMore (): This method should only be called on the media thread.\n");
1013 #endif
1015 if (!CanSeek ())
1016 return MEDIA_FAIL;
1018 if (source->CanSeekToPts ())
1019 return SeekToPts (pts);
1021 // We know 0 is at the beginning of the media, so just optimize this case slightly
1022 if (pts == 0) {
1023 ResetAll ();
1024 next_packet_index = 0;
1025 return MEDIA_SUCCESS;
1028 // For each stream we need to find a keyframe whose pts is below the requested one.
1029 // Read a packet, and check each payload for keyframes. If we don't find one, read
1030 // the previous packet, and check again.
1032 MediaResult result = MEDIA_FAIL;
1033 guint64 start_pi = EstimatePacketIndexOfPts (pts); // The packet index we start testing for key frames.
1034 guint64 tested_counter = 0; // The number of packet indices we have tested.
1035 guint64 test_pi = 0; // The packet index we're currently testing.
1036 bool found_all_highest = false;
1037 bool found_all_keyframes = false;
1038 bool found_keyframe [128]; // If we've found a key frame below the requested pts.
1039 bool found_above [128]; // If we've found a frame which is above the requested pts.
1040 guint64 highest_pts [128]; // The highest key frame pts below the requested pts.
1041 guint64 highest_pi [128]; // The packet index where we found the highest key frame (see above).
1043 for (int i = 0; i < 128; i++) {
1044 found_keyframe [i] = readers [i] == NULL;
1045 found_above [i] = readers [i] == NULL;
1046 highest_pts [i] = 0;
1047 highest_pi [i] = G_MAXUINT64;
1050 // Start with the latest available packet, otherwise we may end up waiting for some position
1051 // which is way ahead of the position we'll actually end up wanting
1052 // (if the initial start_pi estimate is way off)
1053 if (start_pi > GetLastAvailablePacketIndex ())
1054 start_pi = GetLastAvailablePacketIndex ();
1056 do {
1057 // We can't read before the first packet
1058 if (start_pi < tested_counter)
1059 break;
1061 test_pi = start_pi - tested_counter++;
1063 ASFPacket *packet = NULL;
1064 result = parser->ReadPacket (&packet, test_pi);
1066 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Searching packet index %llu for key frames..\n", pts, test_pi);
1068 if (result == MEDIA_INVALID_DATA) {
1069 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Skipping invalid packet (index: %llu)\n", pts, test_pi);
1070 if (packet)
1071 packet->unref ();
1072 continue;
1075 if (result == MEDIA_NOT_ENOUGH_DATA) {
1076 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): not enough data (index: %llu)\n", pts, test_pi);
1077 if (packet)
1078 packet->unref ();
1079 return result;
1082 if (!MEDIA_SUCCEEDED (result)) {
1083 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): could not read more packets (error: %i)\n", pts, (int) result);
1084 if (packet)
1085 packet->unref ();;
1086 break;
1089 asf_single_payload** payloads = packet->payloads->payloads;
1090 for (int i = 0; payloads [i] != NULL; i++) {
1091 asf_single_payload *payload = payloads [i];
1092 int stream_id = payload->stream_id;
1093 guint64 payload_pts = MilliSeconds_ToPts (payload->get_presentation_time () - parser->GetFileProperties ()->preroll);
1094 ASFFrameReader *reader = readers [stream_id];
1096 // Ignore payloads for streams we're not handling
1097 if (reader == NULL)
1098 continue;
1100 reader->GetStream ()->SetLastAvailablePts (payload_pts);
1102 // We're not interested in payloads with pts above the requested pts
1103 if (payload_pts > pts) {
1104 found_above [stream_id] = true;
1105 continue;
1108 // We've already found a key frame for the given stream, no need to look for another one.
1109 if (found_keyframe [stream_id])
1110 continue;
1112 // We're not interested in payloads which doesn't represent the start of a frame
1113 if (payload->offset_into_media_object != 0)
1114 continue;
1116 // We're only interested in key frames.
1117 if (!payload->is_key_frame && !reader->IsAudio ())
1118 continue;
1120 // We've found a key frame with pts below the requested pts.
1121 found_keyframe [stream_id] = true;
1122 highest_pts [stream_id] = MAX (highest_pts [stream_id], payload_pts);
1123 highest_pi [stream_id] = highest_pi [stream_id] == G_MAXUINT64 ? test_pi : MAX (highest_pi [stream_id], test_pi);
1124 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Found key frame of stream #%i with pts %llu in packet index %llu\n", pts, stream_id, payload_pts, test_pi);
1127 packet->unref ();;
1129 // Check if we found key frames for all streams, if not, continue looping.
1130 found_all_keyframes = true;
1131 for (int i = 0; i < 128; i++) {
1132 if (!found_keyframe [i]) {
1133 found_all_keyframes = false;
1134 break;
1137 } while (!found_all_keyframes);
1139 // Check if we found key frames for all streams, if not, just return false.
1140 // We haven't changed any reader state, so the readers will continue
1141 // returning data as if nothing had happened.
1142 for (int i = 0; i < 128; i++) {
1143 if (!found_keyframe [i]) {
1144 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Could not find the requested pts.\n", pts);
1145 return MEDIA_FAIL;
1149 // Now we have a packet index we know has key frames whose pts is below the
1150 // requested pts in all streams. We do not know if those key frames are the key frames
1151 // immediately before the requested pts (an example: we might have
1152 // found the first keyframe in every stream when we wanted to seek to the last
1153 // pts). We need to continue reading ahead finding key frames with pts below than the
1154 // requested one, until we find a frame with pts above the requested one, in which case
1155 // we know that we've found the key frame immediately before the requested pts.
1157 tested_counter = 1; // Since we've already tested start_pi, now we want to start with start_pi + 1.
1158 do {
1159 // Make this check before reading any packets, since we might already have found
1160 // all the highest packet indices.
1161 found_all_highest = true;
1162 for (int i = 0; i < 128; i++) {
1163 if (!found_above [i]) {
1164 found_all_highest = false;
1165 break;
1168 if (found_all_highest)
1169 break;
1171 test_pi = start_pi + tested_counter++;
1173 ASFPacket *packet = NULL;
1174 result = parser->ReadPacket (&packet, test_pi);
1176 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Searching packet index %llu for higher key frames..\n", pts, test_pi);
1178 if (result == MEDIA_INVALID_DATA) {
1179 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Skipping invalid packet (index: %llu)\n", pts, test_pi);
1180 if (packet)
1181 packet->unref ();;
1182 continue;
1185 if (result == MEDIA_NOT_ENOUGH_DATA) {
1186 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Not enough data (index: %llu)\n", pts, test_pi);
1187 if (packet)
1188 packet->unref ();
1189 return result;
1192 if (!MEDIA_SUCCEEDED (result)) {
1193 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): could not read more packets (error: %i)\n", pts, (int) result);
1194 if (packet)
1195 packet->unref ();;
1196 break;
1199 if (packet->payloads != NULL) {
1200 asf_single_payload** payloads = packet->payloads->payloads;
1201 for (int i = 0; payloads [i] != NULL; i++) {
1202 asf_single_payload *payload = payloads [i];
1203 int stream_id = payload->stream_id;
1204 guint64 payload_pts = MilliSeconds_ToPts (payload->get_presentation_time () - parser->GetFileProperties ()->preroll);
1205 ASFFrameReader *reader = readers [stream_id];
1207 // Ignore payloads for streams we're not handling
1208 if (reader == NULL)
1209 continue;
1211 reader->GetStream ()->SetLastAvailablePts (payload_pts);
1213 // Found a pts above the requested pts, save it.
1214 if (payload_pts > pts) {
1215 found_above [stream_id] = true;
1216 continue;
1219 // We've already found a higher pts for the given stream, no need to look for another one.
1220 if (found_above [stream_id])
1221 continue;
1223 // We're not interested in payloads which doesn't represent the start of a frame
1224 if (payload->offset_into_media_object != 0)
1225 continue;
1227 // We're only interested in key frames.
1228 if (!payload->is_key_frame && !reader->IsAudio ())
1229 continue;
1231 // We've found another key frame which is below the requested one
1232 highest_pts [stream_id] = MAX (highest_pts [stream_id], payload_pts);
1233 highest_pi [stream_id] = test_pi;
1235 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Found higher key frame of stream #%i with pts %llu in packet index %llu\n", pts, stream_id, payload_pts, test_pi);
1239 packet->unref ();;
1240 } while (true);
1242 // Finally we have all the data we need.
1243 ResetAll ();
1245 test_pi = G_MAXUINT64;
1246 for (int i = 0; i < 128; i++) {
1247 if (readers [i] == NULL)
1248 continue;
1250 // Find the packet index for which it is true that all streams have a key frame below the requested pts.
1251 test_pi = MIN (test_pi, highest_pi [i]);
1252 // Set the first pts to be returned by each reader to the highest key-frame pts we found.
1253 readers [i]->SetFirstPts (highest_pts [i]);
1256 // Don't return any frames before the pts we seeked to.
1257 next_packet_index = (test_pi == G_MAXUINT64) ? 0 : test_pi;
1259 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Seeked to packet index %lld.\n", pts, test_pi);
1261 return MEDIA_SUCCESS;
1264 guint64
1265 ASFReader::GetLastAvailablePacketIndex ()
1267 gint64 last_pos = source->GetLastAvailablePosition ();
1268 guint64 pi;
1270 if (last_pos < parser->GetPacketOffset (0) + parser->GetPacketSize ()) {
1271 LOG_ASF ("ASFReader::GetLastAvailablePacketIndex (): returing 0 (not a single packet available)\n");
1272 return 0;
1275 pi = parser->GetPacketIndex (last_pos);
1277 if (pi == 0) {
1278 LOG_ASF ("ASFReader::GetLastAvailablePacketIndex (): returing 0 (only first packet available)\n");
1279 return 0;
1282 // We want the packet just before the one which contains the last available position.
1283 pi--;
1285 return pi;
1289 * ASFFrameReader
1292 ASFFrameReader::ASFFrameReader (ASFParser *parser, int stream_number, ASFDemuxer *demuxer, ASFReader *reader, IMediaStream *stream)
1294 this->reader = reader;
1295 this->stream_number = stream_number;
1296 this->parser = parser;
1297 this->demuxer = demuxer;
1298 this->stream = stream;
1299 this->stream->ref ();
1300 first = NULL;
1301 last = NULL;
1302 size = 0;
1303 pts = 0;
1304 payloads = NULL;
1306 payloads_size = 0;
1307 payloads = NULL;
1309 first_pts = 0;
1311 index = NULL;
1312 index_size = 0;
1313 key_frames_only = true;
1314 positioned = false;
1315 buffer_underflow = false;
1318 ASFFrameReader::~ASFFrameReader ()
1320 RemoveAll ();
1322 if (payloads != NULL) {
1323 for (int i = 0; payloads[i]; i++)
1324 delete payloads[i];
1326 g_free (payloads);
1329 g_free (index);
1331 if (stream) {
1332 stream->unref ();
1333 stream = NULL;
1337 void
1338 ASFFrameReader::Reset ()
1340 key_frames_only = true;
1341 first_pts = 0;
1342 if (payloads != NULL) {
1343 for (int i = 0; payloads [i]; i++) {
1344 delete payloads [i];
1345 payloads [i] = NULL;
1348 RemoveAll ();
1351 bool
1352 ASFFrameReader::IsAudio ()
1354 return IsAudio (StreamId ());
1357 bool
1358 ASFFrameReader::IsAudio (int stream)
1360 const asf_stream_properties *asp = parser->GetStream (stream);
1361 return asp != NULL && asp->is_audio ();
1364 void
1365 ASFFrameReader::AddFrameIndex (guint64 packet_index)
1367 // No need to create an index if we can't seek.
1368 if (!reader->CanSeek ())
1369 return;
1371 gint64 packet_count = parser->GetPacketCount ();
1373 // Create the index.
1374 if (index_size == 0) {
1375 if (packet_count > 0xFFFF) {
1376 // This is some really huge file (or a corrupted file).
1377 // Don't create any indices, since it would consume a whole lot of memory.
1378 //printf ("ASFFrameReader::AddFrameIndex (): Not creating index, too many packets to track (%" G_GUINT64_FORMAT ")\n", packet_count);
1379 return;
1382 // Max size here is 0xFFFF packets * 16 bytes per index = 1.048.560 bytes
1383 index_size = packet_count;
1385 // Don't create any indices if there are no packets.
1386 if (index_size == 0)
1387 return;
1389 index = (ASFFrameReaderIndex*) g_malloc0 (index_size * sizeof (ASFFrameReaderIndex));
1391 //printf ("ASFFrameReader::AddFrameIndex (): Created index: stream_count: %i, packet_count: %lld, index_size: %i, item size: %i, gives index size: %i bytes\n", stream_count, packet_count, index_size, sizeof (ASFFrameReaderIndex), index_size * sizeof (ASFFrameReaderIndex));
1393 if (index == NULL) {
1394 index_size = 0;
1395 return;
1398 for (int i = 0; i < (int) packet_count; i++) {
1399 index [i].start_pts = INVALID_START_PTS;
1403 // index_size can't be 0 here.
1404 guint32 k = MIN (packet_index, index_size - 1);
1405 guint64 current_start = index [k].start_pts;
1406 index [k].start_pts = MIN (index [k].start_pts, Pts ());
1407 index [k].end_pts = MAX (index [k].end_pts, Pts ());
1408 if (k > 1 && current_start != INVALID_START_PTS) {
1409 index [k].start_pts = MAX (index [k - 1].end_pts, current_start);
1412 //printf ("ASFFrameReader::AddFrameIndex (%" G_GUINT64_FORMAT "). k = %u, start_pts = %llu, end_pts = %llu, stream = %i\n", packet_index, k, index [k].start_pts, index [k].end_pts, stream_number);
1415 guint32
1416 ASFFrameReader::FrameSearch (guint64 pts)
1418 for (guint32 i = 0; i < index_size; i++) {
1419 //printf ("ASFFrameReader::FrameSearch (%" G_GUINT64_FORMAT "): Checking start_pts: %llu, end_pts: %llu, pi: %i\n", pts, index [i].start_pts, index [i].end_pts, index [i].packet_index);
1421 if (index [i].start_pts == INVALID_START_PTS)
1422 continue; // This index isn't set
1424 if (index [i].start_pts > pts) {
1425 //printf ("ASFFrameReader::FrameSearch (%" G_GUINT64_FORMAT "): index not created for the desired pts (found starting pts after the requested one)\n", pts);
1426 return G_MAXUINT32;
1429 if (index [i].start_pts <= pts && index [i].end_pts >= pts) {
1430 //printf ("ASFFrameReader::FrameSearch (%" G_GUINT64_FORMAT "): found packet index: %i.\n", pts, index [i].packet_index);
1431 return i;
1436 //printf ("ASFFrameReader::FrameSearch (%" G_GUINT64_FORMAT "d): searched entire index and didn't find anything.\n", pts);
1438 return -1;
1441 bool
1442 ASFFrameReader::ResizeList (int size)
1444 asf_single_payload **new_list = NULL;
1446 if (payloads_size >= size && size > 0)
1447 return true;
1449 // Allocate a new list
1450 new_list = (asf_single_payload **) parser->Malloc (sizeof (asf_single_payload*) * (size + 1));
1452 if (new_list == NULL) {
1453 return false;
1456 if (payloads != NULL) {
1457 // Copy the old list to the new one
1458 memcpy (new_list, payloads, payloads_size * sizeof (asf_single_payload*));
1459 g_free (payloads);
1462 payloads = new_list;
1463 payloads_size = size;
1465 return true;
1468 void
1469 ASFFrameReader::SetOnlyKeyFrames ()
1471 key_frames_only = true;
1474 void
1475 ASFFrameReader::SetFirstPts (guint64 pts)
1477 first_pts = pts;
1480 MediaResult
1481 ASFFrameReader::Advance (bool read_if_needed)
1483 MediaResult result = MEDIA_SUCCESS;
1484 MediaResult read_result;
1485 int payload_count = 0;
1486 guint32 media_object_number = 0;
1487 guint64 current_pts = 0;
1488 guint64 first_packet_index = 0; // The packet index where the frame starts.
1489 ASFFrameReaderData* current = NULL;
1491 LOG_ASF ("ASFFrameReader::Advance ().\n");
1493 if (buffer_underflow) {
1494 // Set initial values according to where we left off when the buffer underflowed
1495 for (int i = 0; payloads [i] != NULL; i++) {
1496 payload_count++;
1498 if (payload_count == 0) {
1499 size = 0;
1500 pts = 0;
1501 } else {
1502 media_object_number = payloads [0]->media_object_number;
1503 current_pts = pts;
1504 first_packet_index = G_MAXUINT64;
1506 } else {
1507 // Clear the current list of payloads.
1508 // Most streams has at least once a media object spanning two payloads.
1509 // so we allocate space for two (+ NULL at the end).
1510 if (payloads == NULL) {
1511 if (!ResizeList (2)) {
1512 parser->AddError ("Out of memory.");
1513 return MEDIA_OUT_OF_MEMORY;
1515 } else {
1516 // Free all old payloads, they belong to the previous frame.
1517 for (int i = 0; payloads[i]; i++) {
1518 delete payloads[i];
1519 payloads[i] = NULL;
1522 size = 0;
1523 pts = 0;
1526 current = first;
1528 LOG_ASF ("ASFFrameReader::Advance (): frame data: size = %lld, key = %s, pts = %" G_GUINT64_FORMAT ", stream# = %d, media_object_number = %u.\n",
1529 size, IsKeyFrame () ? "true" : "false", Pts (), StreamId (), media_object_number);
1531 buffer_underflow = false;
1533 while (true) {
1534 // Loop through payloads until we find a payload with the different media number
1535 // than the first payload in the queue.
1537 // Make sure we have any payloads in our queue of payloads
1538 while (current == NULL) {
1539 // We went past the end of the payloads, read another packet to get more data.
1540 current = last; // go back to the last element.
1542 LOG_ASF ("ASFFrameReader::Advance (): No more payloads, requesting more data.\n");
1544 if (!read_if_needed) {
1545 read_result = MEDIA_NO_MORE_DATA;
1546 goto end_frame;
1549 read_result = reader->TryReadMore ();
1550 if (read_result == MEDIA_NO_MORE_DATA) {
1551 // No more data, we've reached the end
1552 LOG_ASF ("ASFFrameReader::Advance (): No more data, payload count: %i\n", payload_count);
1553 if (payload_count == 0)
1554 result = read_result;
1555 goto end_frame;
1556 } else if (read_result == MEDIA_BUFFER_UNDERFLOW) {
1557 result = read_result;
1558 buffer_underflow = true;
1559 goto end_frame;
1560 } else if (!MEDIA_SUCCEEDED (read_result)) {
1561 result = read_result;
1562 goto end_frame;
1563 } else {
1564 if (current == NULL) {
1565 // There were no elements before reading more, our next element is the first one
1566 current = first;
1567 } else {
1568 current = current->next;
1573 LOG_ASF ("ASFFrameReader::Advance (): checking payload, stream: %d, media object number %d, size: %d\n", current->payload->stream_id, current->payload->media_object_number, current->payload->payload_data_length);
1575 asf_single_payload* payload = current->payload;
1576 current_pts = MilliSeconds_ToPts (payload->get_presentation_time () - parser->GetFileProperties ()->preroll);
1578 stream->SetLastAvailablePts (current_pts);
1580 if (current_pts < first_pts) {
1581 ASFFrameReaderData* tmp = current;
1582 current = current->next;
1583 Remove (tmp);
1584 } else {
1585 if (payload_count > 0 && payload->media_object_number != media_object_number) {
1586 // We've found the end of the current frame's payloads
1587 LOG_ASF ("ASFFrameReader::Advance (): reached media object number %i (while reading %i).\n", payload->media_object_number, media_object_number);
1588 goto end_frame;
1591 if (key_frames_only && !IsAudio () && !payload->is_key_frame) {
1592 LOG_ASF ("ASFFrameReader::Advance (): dropped non-key frame, pts: %" G_GUINT64_FORMAT "\n", current_pts);
1593 ASFFrameReaderData* tmp = current;
1594 current = current->next;
1595 Remove (tmp);
1596 continue;
1599 if (payload_count == 0 && payload->offset_into_media_object != 0) {
1600 // This frame isn't complete, it's probably split over several packets (and we haven't read the first of those packets).
1601 LOG_ASF ("ASFFrameReader::Advance (): skipping incomplete frame, pts: %" G_GUINT64_FORMAT ", offset into media object: %i.\n", current_pts, payload->offset_into_media_object);
1602 ASFFrameReaderData *tmp = current;
1603 current = current->next;
1604 Remove (tmp);
1605 continue;
1608 key_frames_only = false;
1609 media_object_number = payload->media_object_number;
1610 first_packet_index = current->packet_index;
1612 // add the payload to the current frame's payloads
1613 payload_count++;
1614 if (payload_count == 1)
1615 this->pts = current_pts;
1616 size += payload->payload_data_length;
1617 if (payload_count > payloads_size) {
1618 if (!ResizeList (payload_count + 3)) {
1619 return false;
1622 payloads [payload_count - 1] = payload;
1623 current->payload = NULL;
1625 // Remove it from the queue
1626 ASFFrameReaderData* tmp = current;
1627 current = current->next;
1628 Remove (tmp);
1631 LOG_ASF ("ASFFrameReader::Advance (): current is %p.\n", current);
1634 end_frame:
1636 printf ("ASFFrameReader::Advance (): frame data: size = %.4lld, key = %s, pts = %.5llu, stream# = %i, media_object_number = %.3u (advanced).",
1637 size, IsKeyFrame () ? "true " : "false", Pts (), StreamNumber (), media_object_number);
1639 dump_int_data (payloads [0]->payload_data, payloads [0]->payload_data_length, 4);
1640 printf ("\n");
1643 if (MEDIA_SUCCEEDED (result)) {
1644 printf ("ASFFrameReader::Advance (): frame data: size = %.4lld, key = %s, Pts = %.5llu = %" G_GUINT64_FORMAT " ms, pts = %.5u, stream# = %i (%s), media_object_number = %.3u (advanced).\n",
1645 size, IsKeyFrame () ? "true " : "false", Pts (), MilliSeconds_FromPts (Pts ()), payloads [0]->presentation_time, StreamId (), stream->GetStreamTypeName (), media_object_number);
1649 if (MEDIA_SUCCEEDED (result)) {
1650 if (first_packet_index != G_MAXUINT64)
1651 AddFrameIndex (first_packet_index);
1654 return result;
1657 gint64
1658 ASFFrameReader::EstimatePtsPosition (guint64 pts)
1660 return parser->GetPacketOffset (MIN (parser->GetPacketCount () - 1, EstimatePacketIndexOfPts (pts) + 1));
1663 guint64
1664 ASFFrameReader::EstimatePacketIndexOfPts (guint64 pts)
1666 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT ")\n", pts);
1668 gint32 counter = 0;
1669 guint64 average = 0; // average duration per packet
1670 guint64 last_good_pi = 0;
1671 guint64 last_good_pts = 0;
1672 guint64 duration = 0;
1673 guint64 total_duration = 0;
1674 guint64 result = 0;
1675 guint64 packet_index = 0;
1677 if (pts == 0) {
1678 return 0;
1681 total_duration = parser->GetFileProperties ()->play_duration - MilliSeconds_ToPts (parser->GetFileProperties ()->preroll);
1682 if (pts >= total_duration) {
1683 return parser->GetPacketCount () - 1;
1686 packet_index = FrameSearch (pts);
1688 if (packet_index != G_MAXUINT32) {
1689 //printf ("ASFFrameReader::GetPositionOfPts (%" G_GUINT64_FORMAT "): Found pts in index, position: %lld, pi: %i\n", pts, parser->GetPacketOffset (packet_index), packet_index);
1690 return packet_index;
1693 for (guint32 i = 0; i < index_size; i++) {
1694 if (!(index [i].start_pts != INVALID_START_PTS && index [i].end_pts > index [i].start_pts))
1695 continue;
1697 if (index [i].start_pts >= pts)
1698 break;
1700 last_good_pi = i;
1701 last_good_pts = index [i].start_pts;
1703 duration = index [i].end_pts - index [i].start_pts;
1704 counter++;
1705 average = (average / (double) counter) * (counter - 1) + (duration / (double) counter);
1707 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT "): Calculated average %llu after pi: %i, duration: %llu, start_pts: %llu, end_pts: %llu\n", pts, average, i, duration, index [i].start_pts, index [i].end_pts);
1710 if (average == 0) {
1711 // calculate packet index from duration
1712 guint64 duration = MAX (1, parser->GetFileProperties ()->play_duration - MilliSeconds_ToPts (parser->GetFileProperties ()->preroll));
1713 double percent = MAX (0, pts / (double) duration);
1714 result = percent * parser->GetPacketCount ();
1715 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT "): No average, calculated by percent %.2f, pi: %i, pts: %llu, preroll: %llu\n", pts, percent, pi, pts, preroll);
1716 } else {
1717 // calculate packet index from the last known packet index / pts and average pts per packet index
1718 last_good_pts = MIN (last_good_pts, pts);
1719 result = last_good_pi + (pts - last_good_pts) / average;
1720 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT "): Calculated by averate %llu, last_good_pts: %llu, pi: %i\n", pts, average, last_good_pts, pi);
1723 result = MAX (0, result);
1724 result = MIN (result, MAX (0, parser->GetPacketCount () - 1));
1726 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT "): Final position: %lld of pi: %i. Total packets: %llu, total duration: %llu\n", pts, parser->GetPacketOffset (pi), pi, parser->GetFileProperties ()->data_packet_count, parser->GetFileProperties ()->play_duration);
1727 return result;
1730 void
1731 ASFFrameReader::AppendPayload (asf_single_payload *payload, guint64 packet_index)
1733 LOG_ASF ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Stream #%i, pts: %i ms\n", payload, packet_index, StreamId (), (int) payload->get_presentation_time () - 5000);
1735 bool advanced;
1736 bool restore = false;
1738 ASFFrameReaderData* node = new ASFFrameReaderData (payload);
1739 node->packet_index = packet_index;
1740 if (first == NULL) {
1741 first = node;
1742 last = node;
1743 } else {
1744 node->prev = last;
1745 last->next = node;
1746 last = node;
1749 if (stream->GetType () == MediaTypeMarker) {
1750 // Here we try to figure out if we have an entire marker or not
1751 // (determined by finding two NULL WCHARs in the data).
1752 // Make a copy of our payloads, Advance will delete them,
1753 // and we might want to keep them until the next payload arrives.
1754 ASFFrameReaderData *clone_head = NULL;
1755 ASFFrameReaderData *clone = NULL;
1756 ASFFrameReaderData *tmp = first;
1757 ASFFrameReaderData *copy = NULL;
1759 while (tmp != NULL) {
1760 copy = new ASFFrameReaderData (tmp->payload->Clone ());
1761 if (clone == NULL) {
1762 clone = copy;
1763 clone_head = clone;
1764 } else {
1765 clone->next = copy;
1766 copy->prev = clone;
1767 clone = clone->next;
1769 tmp = tmp->next;
1772 advanced = MEDIA_SUCCEEDED (Advance (false));
1774 if (advanced) {
1775 // Check if we got all the data
1776 // determined by finding two NULL WCHARs
1777 gint16 *data = (gint16 *) g_malloc (Size ());
1778 int nulls = 0;
1780 if (Write (data)) {
1781 for (guint32 i = 0; i < Size () / 2; i++) {
1782 if (data [i] == 0) {
1783 nulls++;
1784 if (nulls >= 2)
1785 break;
1790 LOG_ASF ("ASFFrameReader::AppendPayload () in data with size %" G_GUINT64_FORMAT " found %i nulls.\n", Size (), nulls);
1792 if (nulls >= 2) {
1793 MarkerStream *marker_stream = (MarkerStream *) stream;
1794 MediaFrame *frame = new MediaFrame (marker_stream);
1795 frame->pts = Pts ();
1796 frame->buflen = Size ();
1797 frame->buffer = (guint8 *) data;
1798 marker_stream->MarkerFound (frame);
1799 frame->unref ();
1800 } else {
1801 restore = true;
1802 g_free (data);
1807 if (restore && first == NULL) {
1808 LOG_ASF ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Restoring nodes.\n", payload, packet_index);
1809 // Restore everything
1810 // Advance () should have consumed all of the ASFFrameReaderDataNodes
1811 // otherwise we're having corruption (since the only way to not have consumed
1812 // all nodes is to get a second payload with a different media object number
1813 // than a first payload, and the first payload doesn't contain 2 NULLs).
1814 first = clone_head;
1815 last = first;
1816 while (last->next != NULL)
1817 last = last->next;
1818 } else {
1819 LOG_ASF ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Freeing copied list of nodes.\n", payload, packet_index);
1820 // Free the copied list of nodes.
1821 tmp = clone_head;
1822 while (tmp != NULL) {
1823 copy = tmp->next;
1824 delete tmp;
1825 tmp = copy;
1829 #if 0
1830 int counter = 0;
1831 node = first;
1832 while (node != NULL) {
1833 counter++;
1834 node = node->next;
1836 printf ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Stream #%i now has %i payloads.\n", payload, packet_index, StreamId (), counter);
1837 #endif
1840 bool
1841 ASFFrameReader::Write (void *dest)
1843 if (payloads == NULL)
1844 return false;
1846 for (int i = 0; payloads[i]; i++) {
1847 memcpy (dest, payloads[i]->payload_data, payloads[i]->payload_data_length);
1848 dest = ((char *) dest) + payloads[i]->payload_data_length;
1851 return true;
1854 void
1855 ASFFrameReader::RemoveAll ()
1857 ASFFrameReaderData* current = first, *next = NULL;
1858 while (current != NULL) {
1859 next = current->next;
1860 delete current;
1861 current = next;
1863 first = NULL;
1864 last = NULL;
1867 void
1868 ASFFrameReader::Remove (ASFFrameReaderData* data)
1870 if (data->prev != NULL)
1871 data->prev->next = data->next;
1873 if (data->next != NULL)
1874 data->next->prev = data->prev;
1876 if (data == first)
1877 first = data->next;
1879 if (data == last)
1880 last = data->prev;
1882 delete data;