Merging gst-plugins-ugly
[platform/upstream/gstreamer.git] / gst / asfdemux / asfpacket.c
1 /* GStreamer ASF/WMV/WMA demuxer
2  * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /* FIXME:
21  *  file:///home/tpm/samples/video/asf//336370-regis-velo862.wmv
22  *  file:///home/tpm/samples/video/asf//336370-eichhoer.wmv
23  * throw errors (not always necessarily) in this code path
24  * (looks like they carry broken payloads/packets though) */
25
26 #include "asfpacket.h"
27
28 #include <gst/gstutils.h>
29 #include <gst/gstinfo.h>
30 #include <string.h>
31
32 #define GST_ASF_PAYLOAD_KF_COMPLETE(stream, payload) (stream->is_video && payload->keyframe && payload->buf_filled >= payload->mo_size)
33
34 /* we are unlikely to deal with lengths > 2GB here any time soon, so just
35  * return a signed int and use that for error reporting */
36 static inline gint
37 asf_packet_read_varlen_int (guint lentype_flags, guint lentype_bit_offset,
38     const guint8 ** p_data, guint * p_size)
39 {
40   static const guint lens[4] = { 0, 1, 2, 4 };
41   guint len, val;
42
43   len = lens[(lentype_flags >> lentype_bit_offset) & 0x03];
44
45   /* will make caller bail out with a short read if there's not enough data */
46   if (G_UNLIKELY (*p_size < len)) {
47     GST_WARNING ("need %u bytes, but only %u bytes available", len, *p_size);
48     return -1;
49   }
50
51   switch (len) {
52     case 0:
53       val = 0;
54       break;
55     case 1:
56       val = GST_READ_UINT8 (*p_data);
57       break;
58     case 2:
59       val = GST_READ_UINT16_LE (*p_data);
60       break;
61     case 4:
62       val = GST_READ_UINT32_LE (*p_data);
63       break;
64     default:
65       val = 0;
66       g_assert_not_reached ();
67   }
68
69   *p_data += len;
70   *p_size -= len;
71
72   return (gint) val;
73 }
74
75 static GstBuffer *
76 asf_packet_create_payload_buffer (AsfPacket * packet, const guint8 ** p_data,
77     guint * p_size, guint payload_len)
78 {
79   guint off;
80
81   g_assert (payload_len <= *p_size);
82
83   off = (guint) (*p_data - packet->bdata);
84   g_assert (off < gst_buffer_get_size (packet->buf));
85
86   *p_data += payload_len;
87   *p_size -= payload_len;
88
89   return gst_buffer_copy_region (packet->buf, GST_BUFFER_COPY_ALL, off,
90       payload_len);
91 }
92
93 static AsfPayload *
94 asf_payload_search_payloads_queue (AsfPayload * payload, GArray * payload_list)
95 {
96   AsfPayload *ret = NULL;
97   gint idx;
98   for (idx = payload_list->len - 1; idx >= 0; idx--) {
99     ret = &g_array_index (payload_list, AsfPayload, idx);
100
101     if (G_UNLIKELY (ret->mo_size == payload->mo_size &&
102             ret->mo_number == payload->mo_number)) {
103       return ret;
104     }
105   }
106   return NULL;
107 }
108
109 static AsfPayload *
110 asf_payload_find_previous_fragment (GstASFDemux * demux, AsfPayload * payload,
111     AsfStream * stream)
112 {
113   AsfPayload *ret = NULL;
114
115   if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
116
117     /* Search in queued payloads list */
118     ret = asf_payload_search_payloads_queue (payload, stream->payloads);
119     if (ret) {
120       GST_DEBUG
121           ("previous fragments found in payloads queue for reverse playback : object ID %d",
122           ret->mo_number);
123       return ret;
124     }
125
126     /* Search in payloads 'to be queued' list */
127     ret = asf_payload_search_payloads_queue (payload, stream->payloads_rev);
128     if (ret) {
129       GST_DEBUG
130           ("previous fragments found in temp payload queue for reverse playback : object ID %d",
131           ret->mo_number);
132       return ret;
133     }
134   } else {
135     if (G_UNLIKELY (stream->payloads->len == 0)) {
136       GST_DEBUG ("No previous fragments to merge with for stream %u",
137           stream->id);
138       return NULL;
139     }
140
141     ret =
142         &g_array_index (stream->payloads, AsfPayload,
143         stream->payloads->len - 1);
144
145     if (G_UNLIKELY (ret->mo_size != payload->mo_size ||
146             ret->mo_number != payload->mo_number || ret->mo_offset != 0)) {
147       if (payload->mo_size != 0) {
148         GST_WARNING ("Previous fragment does not match continued fragment");
149         return NULL;
150       } else {
151         /* Warn about this case, but accept it anyway: files in the wild sometimes
152          * have continued packets where the subsequent fragments say that they're
153          * zero-sized. */
154         GST_WARNING ("Previous fragment found, but current fragment has "
155             "zero size, accepting anyway");
156       }
157     }
158   }
159
160 #if 0
161   if (this_fragment->mo_offset + this_payload_len > first_fragment->mo_size) {
162     GST_WARNING ("Merged fragments would be bigger than the media object");
163     return FALSE;
164   }
165 #endif
166
167   return ret;
168 }
169
170 /* TODO: if we have another payload already queued for this stream and that
171  * payload doesn't have a duration, maybe we can calculate a duration for it
172  * (if the previous timestamp is smaller etc. etc.) */
173 static void
174 gst_asf_payload_queue_for_stream_forward (GstASFDemux * demux,
175     AsfPayload * payload, AsfStream * stream)
176 {
177   GST_DEBUG_OBJECT (demux, "Got payload for stream %d ts:%" GST_TIME_FORMAT,
178       stream->id, GST_TIME_ARGS (payload->ts));
179
180   /* make timestamps start from 0; first_ts will be determined during activation (once we have enough data),
181      which will also update ts of all packets queued before we knew first_ts;  */
182   if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (demux->first_ts)
183           && GST_CLOCK_TIME_IS_VALID (payload->ts))) {
184     if (payload->ts > demux->first_ts)
185       payload->ts -= demux->first_ts;
186     else
187       payload->ts = 0;
188   }
189
190   /* remove any incomplete payloads that will never be completed */
191   while (stream->payloads->len > 0) {
192     AsfPayload *prev;
193     guint idx_last;
194
195     idx_last = stream->payloads->len - 1;
196     prev = &g_array_index (stream->payloads, AsfPayload, idx_last);
197
198     if (G_UNLIKELY (gst_asf_payload_is_complete (prev)))
199       break;
200
201     GST_DEBUG_OBJECT (demux, "Dropping incomplete fragmented media object "
202         "queued for stream %u", stream->id);
203
204     gst_buffer_replace (&prev->buf, NULL);
205     g_array_remove_index (stream->payloads, idx_last);
206
207     /* there's data missing, so there's a discontinuity now */
208     GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
209   }
210
211   /* If we're about to queue a key frame that is before the segment start, we
212    * can ditch any previously queued payloads (which would also be before the
213    * segment start). This makes sure the decoder doesn't decode more than
214    * absolutely necessary after a seek (we don't push out payloads that are
215    * before the segment start until we have at least one that falls within the
216    * segment) */
217   if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
218           payload->ts < demux->segment.start && payload->keyframe)) {
219     GST_DEBUG_OBJECT (demux, "Queueing keyframe before segment start, removing"
220         " %u previously-queued payloads, which would be out of segment too and"
221         " hence don't have to be decoded", stream->payloads->len);
222     while (stream->payloads->len > 0) {
223       AsfPayload *last;
224       guint idx_last;
225
226       idx_last = stream->payloads->len - 1;
227       last = &g_array_index (stream->payloads, AsfPayload, idx_last);
228       gst_buffer_replace (&last->buf, NULL);
229       g_array_remove_index (stream->payloads, idx_last);
230     }
231
232     /* Mark discontinuity (should be done via stream->discont anyway though) */
233     GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
234   }
235
236   g_array_append_vals (stream->payloads, payload, 1);
237 }
238
239 static void
240 gst_asf_payload_queue_for_stream_reverse (GstASFDemux * demux,
241     AsfPayload * payload, AsfStream * stream)
242 {
243   GST_DEBUG_OBJECT (demux, "Got payload for stream %d ts:%" GST_TIME_FORMAT,
244       stream->id, GST_TIME_ARGS (payload->ts));
245
246   if (demux->multiple_payloads) {
247     /* store the payload in temporary buffer, until we parse all payloads in this packet */
248     g_array_append_vals (stream->payloads_rev, payload, 1);
249   } else {
250     if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts))) {
251       g_array_append_vals (stream->payloads, payload, 1);
252       if (GST_ASF_PAYLOAD_KF_COMPLETE (stream, payload)) {
253         stream->kf_pos = stream->payloads->len - 1;
254       }
255     } else {
256       gst_buffer_unref (payload->buf);
257     }
258   }
259 }
260
261
262 static void
263 gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload,
264     AsfStream * stream)
265 {
266   GST_DEBUG_OBJECT (demux, "Got payload for stream %d ts:%" GST_TIME_FORMAT,
267       stream->id, GST_TIME_ARGS (payload->ts));
268
269   if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
270     gst_asf_payload_queue_for_stream_reverse (demux, payload, stream);
271   } else {
272     gst_asf_payload_queue_for_stream_forward (demux, payload, stream);
273   }
274
275 }
276
277 static void
278 asf_payload_parse_replicated_data_extensions (AsfStream * stream,
279     AsfPayload * payload)
280 {
281   AsfPayloadExtension *ext;
282   guint off;
283   guint16 ext_len;
284
285   if (!stream->ext_props.valid || stream->ext_props.payload_extensions == NULL)
286     return;
287
288   off = 8;
289   for (ext = stream->ext_props.payload_extensions; ext->len > 0; ++ext) {
290     ext_len = ext->len;
291     if (ext_len == 0xFFFF) {    /* extension length is determined by first two bytes in replicated data */
292       ext_len = GST_READ_UINT16_LE (payload->rep_data + off);
293       off += 2;
294     }
295     if (G_UNLIKELY (off + ext_len > payload->rep_data_len)) {
296       GST_WARNING ("not enough replicated data for defined extensions");
297       return;
298     }
299     switch (ext->id) {
300       case ASF_PAYLOAD_EXTENSION_DURATION:
301         if (G_LIKELY (ext_len == 2)) {
302           guint16 tdur = GST_READ_UINT16_LE (payload->rep_data + off);
303           /* packet durations of 1ms are mostly invalid */
304           if (tdur != 1)
305             payload->duration = tdur * GST_MSECOND;
306         } else {
307           GST_WARNING ("unexpected DURATION extensions len %u", ext_len);
308         }
309         break;
310       case ASF_PAYLOAD_EXTENSION_SYSTEM_CONTENT:
311         if (G_LIKELY (ext_len == 1)) {
312           guint8 data = payload->rep_data[off];
313
314           payload->interlaced = data & 0x1;
315           payload->rff = data & 0x8;
316           payload->tff = (data & 0x2) || !(data & 0x4);
317           GST_DEBUG ("SYSTEM_CONTENT: interlaced:%d, rff:%d, tff:%d",
318               payload->interlaced, payload->rff, payload->tff);
319         } else {
320           GST_WARNING ("unexpected SYSTEM_CONTE extensions len %u", ext_len);
321         }
322         break;
323       case ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO:
324         if (G_LIKELY (ext_len == 2)) {
325           payload->par_x = payload->rep_data[off];
326           payload->par_y = payload->rep_data[off + 1];
327           GST_DEBUG ("PAR %d / %d", payload->par_x, payload->par_y);
328         } else {
329           GST_WARNING ("unexpected SYSTEM_PIXEL_ASPECT_RATIO extensions len %u",
330               ext_len);
331         }
332         break;
333       case ASF_PAYLOAD_EXTENSION_TIMING:
334       {
335         /* dvr-ms timing - this will override packet timestamp */
336         guint64 time = GST_READ_UINT64_LE (payload->rep_data + off + 8);
337         if (time != 0xFFFFFFFFFFFFFFFF)
338           payload->ts = time * 100;
339         else
340           payload->ts = GST_CLOCK_TIME_NONE;
341       }
342         break;
343       default:
344         GST_LOG ("UNKNOWN PAYLOAD EXTENSION!");
345         break;
346     }
347     off += ext_len;
348   }
349 }
350
351 static gboolean
352 gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet,
353     gint lentype, const guint8 ** p_data, guint * p_size)
354 {
355   AsfPayload payload = { 0, };
356   AsfStream *stream;
357   gboolean is_compressed;
358   guint payload_len;
359   guint stream_num;
360
361   if (G_UNLIKELY (*p_size < 1)) {
362     GST_WARNING_OBJECT (demux, "Short packet!");
363     return FALSE;
364   }
365
366   stream_num = GST_READ_UINT8 (*p_data) & 0x7f;
367   payload.keyframe = ((GST_READ_UINT8 (*p_data) & 0x80) != 0);
368
369   *p_data += 1;
370   *p_size -= 1;
371
372   payload.ts = GST_CLOCK_TIME_NONE;
373   payload.duration = GST_CLOCK_TIME_NONE;
374   payload.par_x = 0;
375   payload.par_y = 0;
376   payload.interlaced = FALSE;
377   payload.tff = FALSE;
378   payload.rff = FALSE;
379
380   payload.mo_number =
381       asf_packet_read_varlen_int (packet->prop_flags, 4, p_data, p_size);
382   payload.mo_offset =
383       asf_packet_read_varlen_int (packet->prop_flags, 2, p_data, p_size);
384   payload.rep_data_len =
385       asf_packet_read_varlen_int (packet->prop_flags, 0, p_data, p_size);
386
387   is_compressed = (payload.rep_data_len == 1);
388
389   GST_LOG_OBJECT (demux, "payload for stream %u", stream_num);
390   GST_LOG_OBJECT (demux, "keyframe   : %s", (payload.keyframe) ? "yes" : "no");
391   GST_LOG_OBJECT (demux, "compressed : %s", (is_compressed) ? "yes" : "no");
392
393   if (G_UNLIKELY (*p_size < payload.rep_data_len)) {
394     GST_WARNING_OBJECT (demux, "Short packet! rep_data_len=%u, size=%u",
395         payload.rep_data_len, *p_size);
396     return FALSE;
397   }
398
399   memcpy (payload.rep_data, *p_data,
400       MIN (sizeof (payload.rep_data), payload.rep_data_len));
401
402   *p_data += payload.rep_data_len;
403   *p_size -= payload.rep_data_len;
404
405   if (G_UNLIKELY (*p_size == 0)) {
406     GST_WARNING_OBJECT (demux, "payload without data!?");
407     return FALSE;
408   }
409
410   /* we use -1 as lentype for a single payload that's the size of the packet */
411   if (G_UNLIKELY ((lentype >= 0 && lentype <= 3))) {
412     payload_len = asf_packet_read_varlen_int (lentype, 0, p_data, p_size);
413     if (*p_size < payload_len) {
414       GST_WARNING_OBJECT (demux, "Short packet! payload_len=%u, size=%u",
415           payload_len, *p_size);
416       return FALSE;
417     }
418   } else {
419     payload_len = *p_size;
420   }
421
422   GST_LOG_OBJECT (demux, "payload length: %u", payload_len);
423
424   stream = gst_asf_demux_get_stream (demux, stream_num);
425
426   if (G_UNLIKELY (stream == NULL)) {
427     if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
428       GST_WARNING_OBJECT (demux, "Payload for unknown stream %u, skipping",
429           stream_num);
430     }
431     if (*p_size < payload_len) {
432       *p_data += *p_size;
433       *p_size = 0;
434     } else {
435       *p_data += payload_len;
436       *p_size -= payload_len;
437     }
438     return TRUE;
439   }
440
441   if (!stream->is_video)
442     stream->kf_pos = 0;
443
444   if (G_UNLIKELY (!is_compressed)) {
445     GST_LOG_OBJECT (demux, "replicated data length: %u", payload.rep_data_len);
446
447     if (payload.rep_data_len >= 8) {
448       payload.mo_size = GST_READ_UINT32_LE (payload.rep_data);
449       payload.ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND;
450       if (G_UNLIKELY (payload.ts < demux->preroll))
451         payload.ts = 0;
452       else
453         payload.ts -= demux->preroll;
454       asf_payload_parse_replicated_data_extensions (stream, &payload);
455
456       GST_LOG_OBJECT (demux, "media object size   : %u", payload.mo_size);
457       GST_LOG_OBJECT (demux, "media object ts     : %" GST_TIME_FORMAT,
458           GST_TIME_ARGS (payload.ts));
459       GST_LOG_OBJECT (demux, "media object dur    : %" GST_TIME_FORMAT,
460           GST_TIME_ARGS (payload.duration));
461     } else if (payload.rep_data_len == 0) {
462       payload.mo_size = 0;
463     } else if (payload.rep_data_len != 0) {
464       GST_WARNING_OBJECT (demux, "invalid replicated data length, very bad");
465       *p_data += payload_len;
466       *p_size -= payload_len;
467       return FALSE;
468     }
469
470     GST_LOG_OBJECT (demux, "media object offset : %u", payload.mo_offset);
471
472     GST_LOG_OBJECT (demux, "payload length: %u", payload_len);
473
474     if (payload_len == 0) {
475       GST_DEBUG_OBJECT (demux, "skipping empty payload");
476     } else if (payload.mo_offset == 0 && payload.mo_size == payload_len) {
477       /* if the media object is not fragmented, just create a sub-buffer */
478       GST_LOG_OBJECT (demux, "unfragmented media object size %u", payload_len);
479       payload.buf = asf_packet_create_payload_buffer (packet, p_data, p_size,
480           payload_len);
481       payload.buf_filled = payload_len;
482       gst_asf_payload_queue_for_stream (demux, &payload, stream);
483     } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
484       /* Handle fragmented payloads for reverse playback */
485       AsfPayload *prev;
486       const guint8 *payload_data = *p_data;
487       prev = asf_payload_find_previous_fragment (demux, &payload, stream);
488
489       if (prev) {
490         gint idx;
491         AsfPayload *p;
492         gst_buffer_fill (prev->buf, payload.mo_offset,
493             payload_data, payload_len);
494         prev->buf_filled += payload_len;
495         if (payload.keyframe && payload.mo_offset == 0) {
496           stream->reverse_kf_ready = TRUE;
497
498           for (idx = stream->payloads->len - 1; idx >= 0; idx--) {
499             p = &g_array_index (stream->payloads, AsfPayload, idx);
500             if (p->mo_number == payload.mo_number) {
501               /* Mark position of KF for reverse play */
502               stream->kf_pos = idx;
503             }
504           }
505         }
506       } else {
507         payload.buf = gst_buffer_new_allocate (NULL, payload.mo_size, NULL);    /* can we use (mo_size - offset) for size? */
508         gst_buffer_fill (payload.buf, payload.mo_offset,
509             payload_data, payload_len);
510         payload.buf_filled = payload.mo_size - (payload.mo_offset);
511         gst_asf_payload_queue_for_stream (demux, &payload, stream);
512       }
513       *p_data += payload_len;
514       *p_size -= payload_len;
515     } else {
516       const guint8 *payload_data = *p_data;
517
518       g_assert (payload_len <= *p_size);
519
520       *p_data += payload_len;
521       *p_size -= payload_len;
522
523       /* n-th fragment of a fragmented media object? */
524       if (payload.mo_offset != 0) {
525         AsfPayload *prev;
526
527         if ((prev =
528                 asf_payload_find_previous_fragment (demux, &payload, stream))) {
529           if (prev->buf == NULL || (payload.mo_size > 0
530                   && payload.mo_size != prev->mo_size)
531               || payload.mo_offset >= gst_buffer_get_size (prev->buf)
532               || payload.mo_offset + payload_len >
533               gst_buffer_get_size (prev->buf)) {
534             GST_WARNING_OBJECT (demux, "Offset doesn't match previous data?!");
535           } else {
536             /* we assume fragments are payloaded with increasing mo_offset */
537             if (payload.mo_offset != prev->buf_filled) {
538               GST_WARNING_OBJECT (demux, "media object payload discontinuity: "
539                   "offset=%u vs buf_filled=%u", payload.mo_offset,
540                   prev->buf_filled);
541             }
542             gst_buffer_fill (prev->buf, payload.mo_offset,
543                 payload_data, payload_len);
544             prev->buf_filled =
545                 MAX (prev->buf_filled, payload.mo_offset + payload_len);
546             GST_LOG_OBJECT (demux, "Merged media object fragments, size now %u",
547                 prev->buf_filled);
548           }
549         } else {
550           GST_DEBUG_OBJECT (demux, "n-th payload fragment, but don't have "
551               "any previous fragment, ignoring payload");
552         }
553       } else {
554         GST_LOG_OBJECT (demux, "allocating buffer of size %u for fragmented "
555             "media object", payload.mo_size);
556         payload.buf = gst_buffer_new_allocate (NULL, payload.mo_size, NULL);
557         gst_buffer_fill (payload.buf, 0, payload_data, payload_len);
558         payload.buf_filled = payload_len;
559
560         gst_asf_payload_queue_for_stream (demux, &payload, stream);
561       }
562     }
563   } else {
564     const guint8 *payload_data;
565     GstClockTime ts, ts_delta;
566     guint num;
567
568     GST_LOG_OBJECT (demux, "Compressed payload, length=%u", payload_len);
569
570     payload_data = *p_data;
571
572     *p_data += payload_len;
573     *p_size -= payload_len;
574
575     ts = payload.mo_offset * GST_MSECOND;
576     if (G_UNLIKELY (ts < demux->preroll))
577       ts = 0;
578     else
579       ts -= demux->preroll;
580     ts_delta = payload.rep_data[0] * GST_MSECOND;
581
582     for (num = 0; payload_len > 0; ++num) {
583       guint sub_payload_len;
584
585       sub_payload_len = GST_READ_UINT8 (payload_data);
586
587       GST_LOG_OBJECT (demux, "subpayload #%u: len=%u, ts=%" GST_TIME_FORMAT,
588           num, sub_payload_len, GST_TIME_ARGS (ts));
589
590       ++payload_data;
591       --payload_len;
592
593       if (G_UNLIKELY (payload_len < sub_payload_len)) {
594         GST_WARNING_OBJECT (demux, "Short payload! %u bytes left", payload_len);
595         return FALSE;
596       }
597
598       if (G_LIKELY (sub_payload_len > 0)) {
599         payload.buf = asf_packet_create_payload_buffer (packet,
600             &payload_data, &payload_len, sub_payload_len);
601         payload.buf_filled = sub_payload_len;
602
603         payload.ts = ts;
604         if (G_LIKELY (ts_delta))
605           payload.duration = ts_delta;
606         else
607           payload.duration = GST_CLOCK_TIME_NONE;
608
609         gst_asf_payload_queue_for_stream (demux, &payload, stream);
610       }
611
612       ts += ts_delta;
613     }
614   }
615
616   return TRUE;
617 }
618
619 GstAsfDemuxParsePacketError
620 gst_asf_demux_parse_packet (GstASFDemux * demux, GstBuffer * buf)
621 {
622   AsfPacket packet = { 0, };
623   GstMapInfo map;
624   const guint8 *data;
625   gboolean has_multiple_payloads;
626   GstAsfDemuxParsePacketError ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE;
627   guint8 ec_flags, flags1;
628   guint size;
629
630   gst_buffer_map (buf, &map, GST_MAP_READ);
631   data = map.data;
632   size = map.size;
633   GST_LOG_OBJECT (demux, "Buffer size: %u", size);
634
635   /* need at least two payload flag bytes, send time, and duration */
636   if (G_UNLIKELY (size < 2 + 4 + 2)) {
637     GST_WARNING_OBJECT (demux, "Packet size is < 8");
638     ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
639     goto done;
640   }
641
642   packet.buf = buf;
643   /* evidently transient */
644   packet.bdata = data;
645
646   ec_flags = GST_READ_UINT8 (data);
647
648   /* skip optional error correction stuff */
649   if ((ec_flags & 0x80) != 0) {
650     guint ec_len_type, ec_len;
651
652     ec_len_type = (ec_flags & 0x60) >> 5;
653     if (ec_len_type == 0) {
654       ec_len = ec_flags & 0x0f;
655     } else {
656       GST_WARNING_OBJECT (demux, "unexpected error correction length type %u",
657           ec_len_type);
658       ec_len = 2;
659     }
660     GST_LOG_OBJECT (demux, "packet has error correction (%u bytes)", ec_len);
661
662     /* still need at least two payload flag bytes, send time, and duration */
663     if (size <= (1 + ec_len) + 2 + 4 + 2) {
664       GST_WARNING_OBJECT (demux, "Packet size is < 8 with Error Correction");
665       ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_FATAL;
666       goto done;
667     }
668
669     data += 1 + ec_len;
670     size -= 1 + ec_len;
671   }
672
673   /* parse payload info */
674   flags1 = GST_READ_UINT8 (data);
675   packet.prop_flags = GST_READ_UINT8 (data + 1);
676
677   data += 2;
678   size -= 2;
679
680   has_multiple_payloads = (flags1 & 0x01) != 0;
681
682   packet.length = asf_packet_read_varlen_int (flags1, 5, &data, &size);
683
684   packet.sequence = asf_packet_read_varlen_int (flags1, 1, &data, &size);
685
686   packet.padding = asf_packet_read_varlen_int (flags1, 3, &data, &size);
687
688   if (G_UNLIKELY (size < 6)) {
689     GST_WARNING_OBJECT (demux, "Packet size is < 6");
690     ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_FATAL;
691     goto done;
692   }
693
694   packet.send_time = GST_READ_UINT32_LE (data) * GST_MSECOND;
695   packet.duration = GST_READ_UINT16_LE (data + 4) * GST_MSECOND;
696
697   data += 4 + 2;
698   size -= 4 + 2;
699
700   GST_LOG_OBJECT (demux, "flags            : 0x%x", flags1);
701   GST_LOG_OBJECT (demux, "multiple payloads: %u", has_multiple_payloads);
702   GST_LOG_OBJECT (demux, "packet length    : %u", packet.length);
703   GST_LOG_OBJECT (demux, "sequence         : %u", packet.sequence);
704   GST_LOG_OBJECT (demux, "padding          : %u", packet.padding);
705   GST_LOG_OBJECT (demux, "send time        : %" GST_TIME_FORMAT,
706       GST_TIME_ARGS (packet.send_time));
707
708   GST_LOG_OBJECT (demux, "duration         : %" GST_TIME_FORMAT,
709       GST_TIME_ARGS (packet.duration));
710
711   if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
712       && demux->seek_to_cur_pos == TRUE) {
713     /* For reverse playback, initially parse packets forward until we reach packet with 'seek' timestamp */
714     if (packet.send_time - demux->preroll > demux->segment.stop) {
715       demux->seek_to_cur_pos = FALSE;
716     }
717     ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE;
718     goto done;
719   }
720
721   if (G_UNLIKELY (packet.padding == (guint) - 1 || size < packet.padding)) {
722     GST_WARNING_OBJECT (demux, "No padding, or padding bigger than buffer");
723     ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
724     goto done;
725   }
726
727   size -= packet.padding;
728
729   /* adjust available size for parsing if there's less actual packet data for
730    * parsing than there is data in bytes (for sample see bug 431318) */
731   if (G_UNLIKELY (packet.length != 0 && packet.padding == 0
732           && packet.length < demux->packet_size)) {
733     GST_LOG_OBJECT (demux, "shortened packet with implicit padding, "
734         "adjusting available data size");
735     if (size < demux->packet_size - packet.length) {
736       /* the buffer is smaller than the implicit padding */
737       GST_WARNING_OBJECT (demux, "Buffer is smaller than the implicit padding");
738       ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
739       goto done;
740     } else {
741       /* subtract the implicit padding */
742       size -= (demux->packet_size - packet.length);
743     }
744   }
745
746   if (has_multiple_payloads) {
747     guint i, num, lentype;
748     demux->multiple_payloads = TRUE;
749
750     if (G_UNLIKELY (size < 1)) {
751       GST_WARNING_OBJECT (demux, "No room more in buffer");
752       ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
753       goto done;
754     }
755
756     num = (GST_READ_UINT8 (data) & 0x3F) >> 0;
757     lentype = (GST_READ_UINT8 (data) & 0xC0) >> 6;
758
759     ++data;
760     --size;
761
762     GST_LOG_OBJECT (demux, "num payloads     : %u", num);
763
764     for (i = 0; i < num; ++i) {
765       GST_LOG_OBJECT (demux, "Parsing payload %u/%u, size left: %u", i + 1, num,
766           size);
767
768       if (G_UNLIKELY (!gst_asf_demux_parse_payload (demux, &packet, lentype,
769                   &data, &size))) {
770         GST_WARNING_OBJECT (demux, "Failed to parse payload %u/%u", i + 1, num);
771         ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_FATAL;
772         break;
773       }
774     }
775
776     if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
777       /* In reverse playback, we parsed the packet (with multiple payloads) and stored the payloads in temporary queue.
778          Now, add them to the stream's payload queue */
779       for (i = 0; i < demux->num_streams; i++) {
780         AsfStream *s = &demux->stream[i];
781         while (s->payloads_rev->len > 0) {
782           AsfPayload *p;
783           p = &g_array_index (s->payloads_rev, AsfPayload,
784               s->payloads_rev->len - 1);
785           g_array_append_vals (s->payloads, p, 1);
786           if (GST_ASF_PAYLOAD_KF_COMPLETE (s, p)) {
787             /* Mark position of KF for reverse play */
788             s->kf_pos = s->payloads->len - 1;
789           }
790           g_array_remove_index (s->payloads_rev, (s->payloads_rev->len - 1));
791         }
792       }
793     }
794
795   } else {
796     GST_LOG_OBJECT (demux, "Parsing single payload");
797     demux->multiple_payloads = FALSE;
798     if (G_UNLIKELY (!gst_asf_demux_parse_payload (demux, &packet, -1, &data,
799                 &size))) {
800       GST_WARNING_OBJECT (demux, "Failed to parse payload");
801       ret = GST_ASF_DEMUX_PARSE_PACKET_ERROR_RECOVERABLE;
802     }
803   }
804
805 done:
806   gst_buffer_unmap (buf, &map);
807   return ret;
808 }