just kick off another build
[moon.git] / src / asf / asf.cpp
blob028c9290b88c84c5a10ee90d057d916b390286f1
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 bool found_any [128]; // If we've found any frame
1041 guint64 highest_pts [128]; // The highest key frame pts below the requested pts.
1042 guint64 highest_pi [128]; // The packet index where we found the highest key frame (see above).
1044 for (int i = 0; i < 128; i++) {
1045 found_keyframe [i] = readers [i] == NULL;
1046 found_above [i] = readers [i] == NULL;
1047 found_any [i] = readers [i] == NULL;
1048 highest_pts [i] = 0;
1049 highest_pi [i] = G_MAXUINT64;
1052 // Start with the latest available packet, otherwise we may end up waiting for some position
1053 // which is way ahead of the position we'll actually end up wanting
1054 // (if the initial start_pi estimate is way off)
1055 if (start_pi > GetLastAvailablePacketIndex ())
1056 start_pi = GetLastAvailablePacketIndex ();
1058 do {
1059 // We can't read before the first packet
1060 if (start_pi < tested_counter)
1061 break;
1063 test_pi = start_pi - tested_counter++;
1065 ASFPacket *packet = NULL;
1066 result = parser->ReadPacket (&packet, test_pi);
1068 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Searching packet index %llu for key frames..\n", pts, test_pi);
1070 if (result == MEDIA_INVALID_DATA) {
1071 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Skipping invalid packet (index: %llu)\n", pts, test_pi);
1072 if (packet)
1073 packet->unref ();
1074 continue;
1077 if (result == MEDIA_NOT_ENOUGH_DATA) {
1078 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): not enough data (index: %llu)\n", pts, test_pi);
1079 if (packet)
1080 packet->unref ();
1081 return result;
1084 if (!MEDIA_SUCCEEDED (result)) {
1085 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): could not read more packets (error: %i)\n", pts, (int) result);
1086 if (packet)
1087 packet->unref ();;
1088 break;
1091 asf_single_payload** payloads = packet->payloads->payloads;
1092 for (int i = 0; payloads [i] != NULL; i++) {
1093 asf_single_payload *payload = payloads [i];
1094 int stream_id = payload->stream_id;
1095 guint64 payload_pts = MilliSeconds_ToPts (payload->get_presentation_time () - parser->GetFileProperties ()->preroll);
1096 ASFFrameReader *reader = readers [stream_id];
1098 // Ignore payloads for streams we're not handling
1099 if (reader == NULL)
1100 continue;
1102 reader->GetStream ()->SetLastAvailablePts (payload_pts);
1104 // We're not interested in payloads with pts above the requested pts
1105 if (payload_pts > pts) {
1106 found_above [stream_id] = true;
1107 continue;
1110 // We've already found a key frame for the given stream, no need to look for another one.
1111 if (found_keyframe [stream_id])
1112 continue;
1114 // We're not interested in payloads which doesn't represent the start of a frame
1115 if (payload->offset_into_media_object != 0)
1116 continue;
1118 // We're only interested in key frames.
1119 if (!payload->is_key_frame && !reader->IsAudio ())
1120 continue;
1122 // We've found a key frame with pts below the requested pts.
1123 found_keyframe [stream_id] = true;
1124 highest_pts [stream_id] = MAX (highest_pts [stream_id], payload_pts);
1125 highest_pi [stream_id] = highest_pi [stream_id] == G_MAXUINT64 ? test_pi : MAX (highest_pi [stream_id], test_pi);
1126 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);
1129 packet->unref ();;
1131 // Check if we found key frames for all streams, if not, continue looping.
1132 found_all_keyframes = true;
1133 for (int i = 0; i < 128; i++) {
1134 if (test_pi == 0 && !found_any [i]) {
1135 // this is a lie, we haven't found a keyframe.
1136 // but we've searched backwards until the first packet, and we didn't find *any* frame (for this stream),
1137 // which means that there are no frames from the point where we started searching backwards
1138 // untill the first packet. In this case we just assume that there is a keyframe at pts 0 for
1139 // this stream.
1140 found_keyframe [i] = true;
1141 highest_pts [i] = 0;
1142 highest_pi [0] = 0;
1145 if (!found_keyframe [i]) {
1146 found_all_keyframes = false;
1147 break;
1150 } while (!found_all_keyframes);
1152 // Check if we found key frames for all streams, if not, just return false.
1153 // We haven't changed any reader state, so the readers will continue
1154 // returning data as if nothing had happened.
1155 for (int i = 0; i < 128; i++) {
1156 if (!found_keyframe [i]) {
1157 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Could not find the requested pts.\n", pts);
1158 return MEDIA_FAIL;
1162 // Now we have a packet index we know has key frames whose pts is below the
1163 // requested pts in all streams. We do not know if those key frames are the key frames
1164 // immediately before the requested pts (an example: we might have
1165 // found the first keyframe in every stream when we wanted to seek to the last
1166 // pts). We need to continue reading ahead finding key frames with pts below than the
1167 // requested one, until we find a frame with pts above the requested one, in which case
1168 // we know that we've found the key frame immediately before the requested pts.
1170 tested_counter = 1; // Since we've already tested start_pi, now we want to start with start_pi + 1.
1171 do {
1172 // Make this check before reading any packets, since we might already have found
1173 // all the highest packet indices.
1174 found_all_highest = true;
1175 for (int i = 0; i < 128; i++) {
1176 if (!found_above [i]) {
1177 found_all_highest = false;
1178 break;
1181 if (found_all_highest)
1182 break;
1184 test_pi = start_pi + tested_counter++;
1186 ASFPacket *packet = NULL;
1187 result = parser->ReadPacket (&packet, test_pi);
1189 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Searching packet index %llu for higher key frames..\n", pts, test_pi);
1191 if (result == MEDIA_INVALID_DATA) {
1192 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Skipping invalid packet (index: %llu)\n", pts, test_pi);
1193 if (packet)
1194 packet->unref ();;
1195 continue;
1198 if (result == MEDIA_NOT_ENOUGH_DATA) {
1199 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Not enough data (index: %llu)\n", pts, test_pi);
1200 if (packet)
1201 packet->unref ();
1202 return result;
1205 if (!MEDIA_SUCCEEDED (result)) {
1206 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): could not read more packets (error: %i)\n", pts, (int) result);
1207 if (packet)
1208 packet->unref ();;
1209 break;
1212 if (packet->payloads != NULL) {
1213 asf_single_payload** payloads = packet->payloads->payloads;
1214 for (int i = 0; payloads [i] != NULL; i++) {
1215 asf_single_payload *payload = payloads [i];
1216 int stream_id = payload->stream_id;
1217 guint64 payload_pts = MilliSeconds_ToPts (payload->get_presentation_time () - parser->GetFileProperties ()->preroll);
1218 ASFFrameReader *reader = readers [stream_id];
1220 // Ignore payloads for streams we're not handling
1221 if (reader == NULL)
1222 continue;
1224 reader->GetStream ()->SetLastAvailablePts (payload_pts);
1226 // Found a pts above the requested pts, save it.
1227 if (payload_pts > pts) {
1228 found_above [stream_id] = true;
1229 continue;
1232 // We've already found a higher pts for the given stream, no need to look for another one.
1233 if (found_above [stream_id])
1234 continue;
1236 // We're not interested in payloads which doesn't represent the start of a frame
1237 if (payload->offset_into_media_object != 0)
1238 continue;
1240 // We're only interested in key frames.
1241 if (!payload->is_key_frame && !reader->IsAudio ())
1242 continue;
1244 // We've found another key frame which is below the requested one
1245 highest_pts [stream_id] = MAX (highest_pts [stream_id], payload_pts);
1246 highest_pi [stream_id] = test_pi;
1248 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);
1252 packet->unref ();;
1253 } while (true);
1255 // Finally we have all the data we need.
1256 ResetAll ();
1258 test_pi = G_MAXUINT64;
1259 for (int i = 0; i < 128; i++) {
1260 if (readers [i] == NULL)
1261 continue;
1263 // Find the packet index for which it is true that all streams have a key frame below the requested pts.
1264 test_pi = MIN (test_pi, highest_pi [i]);
1265 // Set the first pts to be returned by each reader to the highest key-frame pts we found.
1266 readers [i]->SetFirstPts (highest_pts [i]);
1269 // Don't return any frames before the pts we seeked to.
1270 next_packet_index = (test_pi == G_MAXUINT64) ? 0 : test_pi;
1272 LOG_ASF ("ASFReader::Seek (%" G_GUINT64_FORMAT "): Seeked to packet index %lld.\n", pts, test_pi);
1274 return MEDIA_SUCCESS;
1277 guint64
1278 ASFReader::GetLastAvailablePacketIndex ()
1280 gint64 last_pos = source->GetLastAvailablePosition ();
1281 guint64 pi;
1283 if (last_pos < parser->GetPacketOffset (0) + parser->GetPacketSize ()) {
1284 LOG_ASF ("ASFReader::GetLastAvailablePacketIndex (): returing 0 (not a single packet available)\n");
1285 return 0;
1288 pi = parser->GetPacketIndex (last_pos);
1290 if (pi == 0) {
1291 LOG_ASF ("ASFReader::GetLastAvailablePacketIndex (): returing 0 (only first packet available)\n");
1292 return 0;
1295 // We want the packet just before the one which contains the last available position.
1296 pi--;
1298 return pi;
1302 * ASFFrameReader
1305 ASFFrameReader::ASFFrameReader (ASFParser *parser, int stream_number, ASFDemuxer *demuxer, ASFReader *reader, IMediaStream *stream)
1307 this->reader = reader;
1308 this->stream_number = stream_number;
1309 this->parser = parser;
1310 this->demuxer = demuxer;
1311 this->stream = stream;
1312 this->stream->ref ();
1313 first = NULL;
1314 last = NULL;
1315 size = 0;
1316 pts = 0;
1317 payloads = NULL;
1319 payloads_size = 0;
1320 payloads = NULL;
1322 first_pts = 0;
1324 index = NULL;
1325 index_size = 0;
1326 key_frames_only = true;
1327 positioned = false;
1328 buffer_underflow = false;
1331 ASFFrameReader::~ASFFrameReader ()
1333 RemoveAll ();
1335 if (payloads != NULL) {
1336 for (int i = 0; payloads[i]; i++)
1337 delete payloads[i];
1339 g_free (payloads);
1342 g_free (index);
1344 if (stream) {
1345 stream->unref ();
1346 stream = NULL;
1350 void
1351 ASFFrameReader::Reset ()
1353 key_frames_only = true;
1354 first_pts = 0;
1355 if (payloads != NULL) {
1356 for (int i = 0; payloads [i]; i++) {
1357 delete payloads [i];
1358 payloads [i] = NULL;
1361 RemoveAll ();
1364 bool
1365 ASFFrameReader::IsAudio ()
1367 return IsAudio (StreamId ());
1370 bool
1371 ASFFrameReader::IsAudio (int stream)
1373 const asf_stream_properties *asp = parser->GetStream (stream);
1374 return asp != NULL && asp->is_audio ();
1377 void
1378 ASFFrameReader::AddFrameIndex (guint64 packet_index)
1380 // No need to create an index if we can't seek.
1381 if (!reader->CanSeek ())
1382 return;
1384 gint64 packet_count = parser->GetPacketCount ();
1386 // Create the index.
1387 if (index_size == 0) {
1388 if (packet_count > 0xFFFF) {
1389 // This is some really huge file (or a corrupted file).
1390 // Don't create any indices, since it would consume a whole lot of memory.
1391 //printf ("ASFFrameReader::AddFrameIndex (): Not creating index, too many packets to track (%" G_GUINT64_FORMAT ")\n", packet_count);
1392 return;
1395 // Max size here is 0xFFFF packets * 16 bytes per index = 1.048.560 bytes
1396 index_size = packet_count;
1398 // Don't create any indices if there are no packets.
1399 if (index_size == 0)
1400 return;
1402 index = (ASFFrameReaderIndex*) g_malloc0 (index_size * sizeof (ASFFrameReaderIndex));
1404 //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));
1406 if (index == NULL) {
1407 index_size = 0;
1408 return;
1411 for (int i = 0; i < (int) packet_count; i++) {
1412 index [i].start_pts = INVALID_START_PTS;
1416 // index_size can't be 0 here.
1417 guint32 k = MIN (packet_index, index_size - 1);
1418 guint64 current_start = index [k].start_pts;
1419 index [k].start_pts = MIN (index [k].start_pts, Pts ());
1420 index [k].end_pts = MAX (index [k].end_pts, Pts ());
1421 if (k > 1 && current_start != INVALID_START_PTS) {
1422 index [k].start_pts = MAX (index [k - 1].end_pts, current_start);
1425 //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);
1428 guint32
1429 ASFFrameReader::FrameSearch (guint64 pts)
1431 for (guint32 i = 0; i < index_size; i++) {
1432 //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);
1434 if (index [i].start_pts == INVALID_START_PTS)
1435 continue; // This index isn't set
1437 if (index [i].start_pts > pts) {
1438 //printf ("ASFFrameReader::FrameSearch (%" G_GUINT64_FORMAT "): index not created for the desired pts (found starting pts after the requested one)\n", pts);
1439 return G_MAXUINT32;
1442 if (index [i].start_pts <= pts && index [i].end_pts >= pts) {
1443 //printf ("ASFFrameReader::FrameSearch (%" G_GUINT64_FORMAT "): found packet index: %i.\n", pts, index [i].packet_index);
1444 return i;
1449 //printf ("ASFFrameReader::FrameSearch (%" G_GUINT64_FORMAT "d): searched entire index and didn't find anything.\n", pts);
1451 return -1;
1454 bool
1455 ASFFrameReader::ResizeList (int size)
1457 asf_single_payload **new_list = NULL;
1459 if (payloads_size >= size && size > 0)
1460 return true;
1462 // Allocate a new list
1463 new_list = (asf_single_payload **) parser->Malloc (sizeof (asf_single_payload*) * (size + 1));
1465 if (new_list == NULL) {
1466 return false;
1469 if (payloads != NULL) {
1470 // Copy the old list to the new one
1471 memcpy (new_list, payloads, payloads_size * sizeof (asf_single_payload*));
1472 g_free (payloads);
1475 payloads = new_list;
1476 payloads_size = size;
1478 return true;
1481 void
1482 ASFFrameReader::SetOnlyKeyFrames ()
1484 key_frames_only = true;
1487 void
1488 ASFFrameReader::SetFirstPts (guint64 pts)
1490 first_pts = pts;
1493 MediaResult
1494 ASFFrameReader::Advance (bool read_if_needed)
1496 MediaResult result = MEDIA_SUCCESS;
1497 MediaResult read_result;
1498 int payload_count = 0;
1499 guint32 media_object_number = 0;
1500 guint64 current_pts = 0;
1501 guint64 first_packet_index = 0; // The packet index where the frame starts.
1502 ASFFrameReaderData* current = NULL;
1504 LOG_ASF ("ASFFrameReader::Advance ().\n");
1506 if (buffer_underflow) {
1507 // Set initial values according to where we left off when the buffer underflowed
1508 for (int i = 0; payloads [i] != NULL; i++) {
1509 payload_count++;
1511 if (payload_count == 0) {
1512 size = 0;
1513 pts = 0;
1514 } else {
1515 media_object_number = payloads [0]->media_object_number;
1516 current_pts = pts;
1517 first_packet_index = G_MAXUINT64;
1519 } else {
1520 // Clear the current list of payloads.
1521 // Most streams has at least once a media object spanning two payloads.
1522 // so we allocate space for two (+ NULL at the end).
1523 if (payloads == NULL) {
1524 if (!ResizeList (2)) {
1525 parser->AddError ("Out of memory.");
1526 return MEDIA_OUT_OF_MEMORY;
1528 } else {
1529 // Free all old payloads, they belong to the previous frame.
1530 for (int i = 0; payloads[i]; i++) {
1531 delete payloads[i];
1532 payloads[i] = NULL;
1535 size = 0;
1536 pts = 0;
1539 current = first;
1541 LOG_ASF ("ASFFrameReader::Advance (): frame data: size = %lld, key = %s, pts = %" G_GUINT64_FORMAT ", stream# = %d, media_object_number = %u.\n",
1542 size, IsKeyFrame () ? "true" : "false", Pts (), StreamId (), media_object_number);
1544 buffer_underflow = false;
1546 while (true) {
1547 // Loop through payloads until we find a payload with the different media number
1548 // than the first payload in the queue.
1550 // Make sure we have any payloads in our queue of payloads
1551 while (current == NULL) {
1552 // We went past the end of the payloads, read another packet to get more data.
1553 current = last; // go back to the last element.
1555 LOG_ASF ("ASFFrameReader::Advance (): No more payloads, requesting more data.\n");
1557 if (!read_if_needed) {
1558 read_result = MEDIA_NO_MORE_DATA;
1559 goto end_frame;
1562 read_result = reader->TryReadMore ();
1563 if (read_result == MEDIA_NO_MORE_DATA) {
1564 // No more data, we've reached the end
1565 LOG_ASF ("ASFFrameReader::Advance (): No more data, payload count: %i\n", payload_count);
1566 if (payload_count == 0)
1567 result = read_result;
1568 goto end_frame;
1569 } else if (read_result == MEDIA_BUFFER_UNDERFLOW) {
1570 result = read_result;
1571 buffer_underflow = true;
1572 goto end_frame;
1573 } else if (!MEDIA_SUCCEEDED (read_result)) {
1574 result = read_result;
1575 goto end_frame;
1576 } else {
1577 if (current == NULL) {
1578 // There were no elements before reading more, our next element is the first one
1579 current = first;
1580 } else {
1581 current = current->next;
1586 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);
1588 asf_single_payload* payload = current->payload;
1589 current_pts = MilliSeconds_ToPts (payload->get_presentation_time () - parser->GetFileProperties ()->preroll);
1591 stream->SetLastAvailablePts (current_pts);
1593 if (current_pts < first_pts) {
1594 ASFFrameReaderData* tmp = current;
1595 current = current->next;
1596 Remove (tmp);
1597 } else {
1598 if (payload_count > 0 && payload->media_object_number != media_object_number) {
1599 // We've found the end of the current frame's payloads
1600 LOG_ASF ("ASFFrameReader::Advance (): reached media object number %i (while reading %i).\n", payload->media_object_number, media_object_number);
1601 goto end_frame;
1604 if (key_frames_only && !IsAudio () && !payload->is_key_frame) {
1605 LOG_ASF ("ASFFrameReader::Advance (): dropped non-key frame, pts: %" G_GUINT64_FORMAT "\n", current_pts);
1606 ASFFrameReaderData* tmp = current;
1607 current = current->next;
1608 Remove (tmp);
1609 continue;
1612 if (payload_count == 0 && payload->offset_into_media_object != 0) {
1613 // This frame isn't complete, it's probably split over several packets (and we haven't read the first of those packets).
1614 LOG_ASF ("ASFFrameReader::Advance (): skipping incomplete frame, pts: %" G_GUINT64_FORMAT ", offset into media object: %i.\n", current_pts, payload->offset_into_media_object);
1615 ASFFrameReaderData *tmp = current;
1616 current = current->next;
1617 Remove (tmp);
1618 continue;
1621 key_frames_only = false;
1622 media_object_number = payload->media_object_number;
1623 first_packet_index = current->packet_index;
1625 // add the payload to the current frame's payloads
1626 payload_count++;
1627 if (payload_count == 1)
1628 this->pts = current_pts;
1629 size += payload->payload_data_length;
1630 if (payload_count > payloads_size) {
1631 if (!ResizeList (payload_count + 3)) {
1632 return false;
1635 payloads [payload_count - 1] = payload;
1636 current->payload = NULL;
1638 // Remove it from the queue
1639 ASFFrameReaderData* tmp = current;
1640 current = current->next;
1641 Remove (tmp);
1644 LOG_ASF ("ASFFrameReader::Advance (): current is %p.\n", current);
1647 end_frame:
1649 printf ("ASFFrameReader::Advance (): frame data: size = %.4lld, key = %s, pts = %.5llu, stream# = %i, media_object_number = %.3u (advanced).",
1650 size, IsKeyFrame () ? "true " : "false", Pts (), StreamNumber (), media_object_number);
1652 dump_int_data (payloads [0]->payload_data, payloads [0]->payload_data_length, 4);
1653 printf ("\n");
1656 if (MEDIA_SUCCEEDED (result)) {
1657 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",
1658 size, IsKeyFrame () ? "true " : "false", Pts (), MilliSeconds_FromPts (Pts ()), payloads [0]->presentation_time, StreamId (), stream->GetStreamTypeName (), media_object_number);
1662 if (MEDIA_SUCCEEDED (result)) {
1663 if (first_packet_index != G_MAXUINT64)
1664 AddFrameIndex (first_packet_index);
1667 return result;
1670 gint64
1671 ASFFrameReader::EstimatePtsPosition (guint64 pts)
1673 return parser->GetPacketOffset (MIN (parser->GetPacketCount () - 1, EstimatePacketIndexOfPts (pts) + 1));
1676 guint64
1677 ASFFrameReader::EstimatePacketIndexOfPts (guint64 pts)
1679 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT ")\n", pts);
1681 gint32 counter = 0;
1682 guint64 average = 0; // average duration per packet
1683 guint64 last_good_pi = 0;
1684 guint64 last_good_pts = 0;
1685 guint64 duration = 0;
1686 guint64 total_duration = 0;
1687 guint64 result = 0;
1688 guint64 packet_index = 0;
1690 if (pts == 0) {
1691 return 0;
1694 total_duration = parser->GetFileProperties ()->play_duration - MilliSeconds_ToPts (parser->GetFileProperties ()->preroll);
1695 if (pts >= total_duration) {
1696 return parser->GetPacketCount () - 1;
1699 packet_index = FrameSearch (pts);
1701 if (packet_index != G_MAXUINT32) {
1702 //printf ("ASFFrameReader::GetPositionOfPts (%" G_GUINT64_FORMAT "): Found pts in index, position: %lld, pi: %i\n", pts, parser->GetPacketOffset (packet_index), packet_index);
1703 return packet_index;
1706 for (guint32 i = 0; i < index_size; i++) {
1707 if (!(index [i].start_pts != INVALID_START_PTS && index [i].end_pts > index [i].start_pts))
1708 continue;
1710 if (index [i].start_pts >= pts)
1711 break;
1713 last_good_pi = i;
1714 last_good_pts = index [i].start_pts;
1716 duration = index [i].end_pts - index [i].start_pts;
1717 counter++;
1718 average = (average / (double) counter) * (counter - 1) + (duration / (double) counter);
1720 //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);
1723 if (average == 0) {
1724 // calculate packet index from duration
1725 guint64 duration = MAX (1, parser->GetFileProperties ()->play_duration - MilliSeconds_ToPts (parser->GetFileProperties ()->preroll));
1726 double percent = MAX (0, pts / (double) duration);
1727 result = percent * parser->GetPacketCount ();
1728 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT "): No average, calculated by percent %.2f, pi: %i, pts: %llu, preroll: %llu\n", pts, percent, pi, pts, preroll);
1729 } else {
1730 // calculate packet index from the last known packet index / pts and average pts per packet index
1731 last_good_pts = MIN (last_good_pts, pts);
1732 result = last_good_pi + (pts - last_good_pts) / average;
1733 //printf ("ASFFrameReader::GetPacketIndexOfPts (%" G_GUINT64_FORMAT "): Calculated by averate %llu, last_good_pts: %llu, pi: %i\n", pts, average, last_good_pts, pi);
1736 result = MAX (0, result);
1737 result = MIN (result, MAX (0, parser->GetPacketCount () - 1));
1739 //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);
1740 return result;
1743 void
1744 ASFFrameReader::AppendPayload (asf_single_payload *payload, guint64 packet_index)
1746 LOG_ASF ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Stream #%i, pts: %i ms\n", payload, packet_index, StreamId (), (int) payload->get_presentation_time () - 5000);
1748 bool advanced;
1749 bool restore = false;
1751 ASFFrameReaderData* node = new ASFFrameReaderData (payload);
1752 node->packet_index = packet_index;
1753 if (first == NULL) {
1754 first = node;
1755 last = node;
1756 } else {
1757 node->prev = last;
1758 last->next = node;
1759 last = node;
1762 if (stream->GetType () == MediaTypeMarker) {
1763 // Here we try to figure out if we have an entire marker or not
1764 // (determined by finding two NULL WCHARs in the data).
1765 // Make a copy of our payloads, Advance will delete them,
1766 // and we might want to keep them until the next payload arrives.
1767 ASFFrameReaderData *clone_head = NULL;
1768 ASFFrameReaderData *clone = NULL;
1769 ASFFrameReaderData *tmp = first;
1770 ASFFrameReaderData *copy = NULL;
1772 while (tmp != NULL) {
1773 copy = new ASFFrameReaderData (tmp->payload->Clone ());
1774 if (clone == NULL) {
1775 clone = copy;
1776 clone_head = clone;
1777 } else {
1778 clone->next = copy;
1779 copy->prev = clone;
1780 clone = clone->next;
1782 tmp = tmp->next;
1785 advanced = MEDIA_SUCCEEDED (Advance (false));
1787 if (advanced) {
1788 // Check if we got all the data
1789 // determined by finding two NULL WCHARs
1790 gint16 *data = (gint16 *) g_malloc (Size ());
1791 int nulls = 0;
1793 if (Write (data)) {
1794 for (guint32 i = 0; i < Size () / 2; i++) {
1795 if (data [i] == 0) {
1796 nulls++;
1797 if (nulls >= 2)
1798 break;
1803 LOG_ASF ("ASFFrameReader::AppendPayload () in data with size %" G_GUINT64_FORMAT " found %i nulls.\n", Size (), nulls);
1805 if (nulls >= 2) {
1806 MarkerStream *marker_stream = (MarkerStream *) stream;
1807 MediaFrame *frame = new MediaFrame (marker_stream);
1808 frame->pts = Pts ();
1809 frame->buflen = Size ();
1810 frame->buffer = (guint8 *) data;
1811 marker_stream->MarkerFound (frame);
1812 frame->unref ();
1813 } else {
1814 restore = true;
1815 g_free (data);
1820 if (restore && first == NULL) {
1821 LOG_ASF ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Restoring nodes.\n", payload, packet_index);
1822 // Restore everything
1823 // Advance () should have consumed all of the ASFFrameReaderDataNodes
1824 // otherwise we're having corruption (since the only way to not have consumed
1825 // all nodes is to get a second payload with a different media object number
1826 // than a first payload, and the first payload doesn't contain 2 NULLs).
1827 first = clone_head;
1828 last = first;
1829 while (last->next != NULL)
1830 last = last->next;
1831 } else {
1832 LOG_ASF ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Freeing copied list of nodes.\n", payload, packet_index);
1833 // Free the copied list of nodes.
1834 tmp = clone_head;
1835 while (tmp != NULL) {
1836 copy = tmp->next;
1837 delete tmp;
1838 tmp = copy;
1842 #if 0
1843 int counter = 0;
1844 node = first;
1845 while (node != NULL) {
1846 counter++;
1847 node = node->next;
1849 printf ("ASFFrameReader::AppendPayload (%p, %" G_GUINT64_FORMAT "). Stream #%i now has %i payloads.\n", payload, packet_index, StreamId (), counter);
1850 #endif
1853 bool
1854 ASFFrameReader::Write (void *dest)
1856 if (payloads == NULL)
1857 return false;
1859 for (int i = 0; payloads[i]; i++) {
1860 memcpy (dest, payloads[i]->payload_data, payloads[i]->payload_data_length);
1861 dest = ((char *) dest) + payloads[i]->payload_data_length;
1864 return true;
1867 void
1868 ASFFrameReader::RemoveAll ()
1870 ASFFrameReaderData* current = first, *next = NULL;
1871 while (current != NULL) {
1872 next = current->next;
1873 delete current;
1874 current = next;
1876 first = NULL;
1877 last = NULL;
1880 void
1881 ASFFrameReader::Remove (ASFFrameReaderData* data)
1883 if (data->prev != NULL)
1884 data->prev->next = data->next;
1886 if (data->next != NULL)
1887 data->next->prev = data->prev;
1889 if (data == first)
1890 first = data->next;
1892 if (data == last)
1893 last = data->prev;
1895 delete data;