1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#include <stdlib.h>
28#include <string.h>
29
30/* prevent double-defines when it is defined on the command line - as in the test app */
31#ifndef ENABLE_CONTAINERS_LOG_FORMAT
32//#define ENABLE_CONTAINERS_LOG_FORMAT
33#endif
34#ifndef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
35//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
36#endif
37
38#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->object_level
39
40/* For the sanity of the Visual Studio debugger make local names for structures */
41#define VC_CONTAINER_TRACK_MODULE_T ASF_VC_CONTAINER_TRACK_MODULE_T
42#define VC_CONTAINER_MODULE_T ASF_VC_CONTAINER_MODULE_T
43#define VC_CONTAINER_T ASF_VC_CONTAINER_T
44
45#include "containers/core/containers_private.h"
46#include "containers/core/containers_io_helpers.h"
47#include "containers/core/containers_utils.h"
48#include "containers/core/containers_logging.h"
49
50/******************************************************************************
51Defines.
52******************************************************************************/
53#define ASF_TRACKS_MAX 2
54#define ASF_EXTRADATA_MAX 256
55
56#define ASF_MAX_OBJECT_LEVEL 4
57#define ASF_MAX_CONSECUTIVE_UNKNOWN_OBJECTS 5
58#define ASF_MAX_OBJECT_SIZE (1<<29) /* Does not apply to the data object */
59#define ASF_OBJECT_HEADER_SIZE (16+8)
60#define ASF_UNKNOWN_PTS ((uint32_t)(-1))
61#define ASF_MAX_CONSECUTIVE_CORRUPTED_PACKETS 100
62#define ASF_MAX_SEARCH_PACKETS 1000
63
64#define ASF_SKIP_GUID(ctx, size, n) (size -= 16, SKIP_GUID(ctx,n))
65#define ASF_SKIP_U8(ctx, size, n) (size -= 1, SKIP_U8(ctx,n))
66#define ASF_SKIP_U16(ctx, size, n) (size -= 2, SKIP_U16(ctx,n))
67#define ASF_SKIP_U24(ctx, size, n) (size -= 3, SKIP_U24(ctx,n))
68#define ASF_SKIP_U32(ctx, size, n) (size -= 4, SKIP_U32(ctx,n))
69#define ASF_SKIP_U64(ctx, size, n) (size -= 8, SKIP_U64(ctx,n))
70#define ASF_READ_GUID(ctx, size, buffer, n) (size -= 16, READ_GUID(ctx,(uint8_t *)buffer,n))
71#define ASF_READ_U8(ctx, size, n) (size -= 1, READ_U8(ctx,n))
72#define ASF_READ_U16(ctx, size, n) (size -= 2, READ_U16(ctx,n))
73#define ASF_READ_U24(ctx, size, n) (size -= 3, READ_U24(ctx,n))
74#define ASF_READ_U32(ctx, size, n) (size -= 4, READ_U32(ctx,n))
75#define ASF_READ_U64(ctx, size, n) (size -= 8, READ_U64(ctx,n))
76#define ASF_READ_STRING(ctx, size, buffer, to_read, n) (size -= to_read, READ_STRING_UTF16(ctx,buffer,to_read,n))
77#define ASF_SKIP_STRING(ctx, size, to_read, n) (size -= to_read, SKIP_STRING_UTF16(ctx,to_read,n))
78#define ASF_READ_BYTES(ctx, size, buffer, to_read) (size -= to_read, READ_BYTES(ctx,buffer,to_read))
79#define ASF_SKIP_BYTES(ctx, size, to_read) (size -= to_read, SKIP_BYTES(ctx,to_read))
80
81/* Read variable length field from p_context. */
82#define READ_VLC(p_context, length, value_if_missing, txt) \
83 (length) == 1 ? READ_U8(p_context, txt) : \
84 (length) == 2 ? READ_U16(p_context, txt) : \
85 (length) == 3 ? READ_U32(p_context, txt) : value_if_missing
86
87#define CHECK_POINT(p_context, amount_to_read) do { \
88 if(amount_to_read < 0) return VC_CONTAINER_ERROR_CORRUPTED; \
89 if(STREAM_STATUS(p_context)) return STREAM_STATUS(p_context); } while(0)
90
91/******************************************************************************
92Type definitions.
93******************************************************************************/
94
95/** Context for our reader
96 */
97typedef struct
98{
99 uint64_t start; /* The byte offset start of the current packet in the file */
100 uint32_t size;
101 uint32_t padding_size;
102 uint64_t send_time; /* read in mS, stored in uS */
103 bool eos;
104 bool corrupted;
105 uint16_t bad_packets;
106
107 /* All the different Length Types for the VLC codes */
108 unsigned int replicated_data_lt;
109 unsigned int offset_into_media_object_lt;
110 unsigned int media_object_number_lt;
111 unsigned int payload_lt;
112
113 unsigned int multiple_payloads;
114 unsigned int compressed_payloads;
115
116 uint8_t num_payloads;
117 uint8_t current_payload;
118 uint32_t current_offset; /* The offset in the current packet for the next byte to be read */
119
120 /* Info already read */
121 uint32_t stream_num; /* Stream number and key-frame flag */
122 uint32_t media_object_num;
123 uint32_t media_object_off;
124 uint32_t payload_size;
125 uint32_t subpayload_size;
126
127 /* Info read from the replicated data */
128 uint32_t media_object_size;
129 uint64_t media_object_pts; /**< Presentation timestamp in microseconds */
130 uint64_t media_object_pts_delta; /**< Presentation timestamp delta in microseconds */
131
132} ASF_PACKET_STATE;
133
134typedef struct VC_CONTAINER_TRACK_MODULE_T
135{
136 /* The ID of the stream (the index in the containing array need not be the ID) */
137 unsigned int stream_id;
138 bool b_valid;
139
140 uint8_t extradata[ASF_EXTRADATA_MAX];
141
142 ASF_PACKET_STATE *p_packet_state;
143 ASF_PACKET_STATE local_packet_state;
144
145 /* Simple index structure. Corresponds to the simple index in 6.1 of the spec
146 * This index has locations in packets, not in bytes, and relies on the
147 * file having fixed-length packets - as is required */
148 struct
149 {
150 uint64_t offset; /**< Offset to the start of the simple index data */
151 uint32_t num_entries;
152 int64_t time_interval; /* in uS */
153 bool incomplete; /* The index does not go to the end of the file */
154 } simple_index;
155
156} VC_CONTAINER_TRACK_MODULE_T;
157
158typedef struct VC_CONTAINER_MODULE_T
159{
160 int object_level;
161
162 uint32_t packet_size; /**< Size of a data packet */
163 uint64_t packets_num; /**< Number of packets contained in the data object */
164
165 bool broadcast; /**< Specifies if we are dealing with a broadcast stream */
166 int64_t duration; /**< Duration of the stream in microseconds */
167 int64_t preroll; /**< Duration of the preroll in microseconds. */
168 /* This is the PTS of the first packet; all are offset by this amount. */
169 uint64_t time_offset; /**< Offset added to timestamps in microseconds */
170
171 uint64_t data_offset; /**< Offset to the start of the data packets */
172 int64_t data_size; /**< Size of the data contained in the data object */
173
174 /* The track objects. There's a count of these in VC_CONTAINER_T::tracks_num */
175 VC_CONTAINER_TRACK_T *tracks[ASF_TRACKS_MAX];
176
177 /* Translation table from stream_number to index in the tracks array */
178 unsigned char stream_number_to_index[128];
179
180 /* Data for a top-level index structure as defined in 6.2 of the spec */
181 struct
182 {
183 uint64_t entry_time_interval; /* The time interval between specifiers, scaled to uS */
184 uint32_t specifiers_count; /* The number of specifiers in the file, 0 if no index */
185 uint64_t active_specifiers[ASF_TRACKS_MAX]; /* the specifier in use for each track,
186 * or >=specifiers_count if none */
187 uint64_t specifiers_offset; /* The file address of the first specifier. */
188 uint32_t block_count; /* The number of index blocks */
189 uint64_t blocks_offset; /* The file address of the first block */
190 } top_level_index;
191
192 /* A pointer to the track (in the tracks array) which is to be used with a simple index.
193 * null if there is no such track */
194 ASF_VC_CONTAINER_TRACK_MODULE_T *simple_index_track;
195
196 /* Shared packet state. This is used when the tracks are in sync,
197 and for the track at the earliest position in the file when they are not in sync */
198 ASF_PACKET_STATE packet_state;
199
200} VC_CONTAINER_MODULE_T;
201
202/******************************************************************************
203Function prototypes
204******************************************************************************/
205VC_CONTAINER_STATUS_T asf_reader_open( VC_CONTAINER_T * );
206
207/******************************************************************************
208Prototypes for local functions
209******************************************************************************/
210static VC_CONTAINER_STATUS_T asf_read_object( VC_CONTAINER_T *p_ctx, int64_t size );
211static VC_CONTAINER_STATUS_T asf_read_object_header( VC_CONTAINER_T *p_ctx, int64_t size );
212static VC_CONTAINER_STATUS_T asf_read_object_header_ext( VC_CONTAINER_T *p_ctx, int64_t size );
213static VC_CONTAINER_STATUS_T asf_read_object_file_properties( VC_CONTAINER_T *p_ctx, int64_t size );
214static VC_CONTAINER_STATUS_T asf_read_object_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size );
215static VC_CONTAINER_STATUS_T asf_read_object_ext_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size );
216static VC_CONTAINER_STATUS_T asf_read_object_simple_index( VC_CONTAINER_T *p_ctx, int64_t size );
217static VC_CONTAINER_STATUS_T asf_read_object_index( VC_CONTAINER_T *p_ctx, int64_t size );
218static VC_CONTAINER_STATUS_T asf_read_object_index_parameters( VC_CONTAINER_T *p_ctx, int64_t size );
219static VC_CONTAINER_STATUS_T asf_read_object_data( VC_CONTAINER_T *p_ctx, int64_t size );
220static VC_CONTAINER_STATUS_T asf_read_object_codec_list( VC_CONTAINER_T *p_ctx, int64_t size );
221static VC_CONTAINER_STATUS_T asf_read_object_content_description( VC_CONTAINER_T *p_ctx, int64_t size );
222static VC_CONTAINER_STATUS_T asf_read_object_stream_bitrate_props( VC_CONTAINER_T *p_ctx, int64_t size );
223static VC_CONTAINER_STATUS_T asf_read_object_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size );
224static VC_CONTAINER_STATUS_T asf_read_object_ext_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size );
225static VC_CONTAINER_STATUS_T asf_read_object_adv_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size );
226static VC_CONTAINER_STATUS_T asf_skip_unprocessed_object( VC_CONTAINER_T *p_ctx, int64_t size );
227static VC_CONTAINER_STATUS_T seek_to_positions(VC_CONTAINER_T *p_ctx,
228 uint64_t track_positions[ASF_TRACKS_MAX], int64_t *p_time,
229 VC_CONTAINER_SEEK_FLAGS_T flags, unsigned int start_track,
230 bool seek_on_start_track);
231
232/******************************************************************************
233GUID list for the different ASF objects
234******************************************************************************/
235static const GUID_T asf_guid_header = {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
236static const GUID_T asf_guid_file_props = {0x8CABDCA1, 0xA947, 0x11CF, {0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
237static const GUID_T asf_guid_stream_props = {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
238static const GUID_T asf_guid_ext_stream_props = {0x14E6A5CB, 0xC672, 0x4332, {0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}};
239static const GUID_T asf_guid_data = {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
240static const GUID_T asf_guid_simple_index = {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
241static const GUID_T asf_guid_index = {0xD6E229D3, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
242static const GUID_T asf_guid_index_parameters = {0xD6E229DF, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
243static const GUID_T asf_guid_header_ext = {0x5FBF03B5, 0xA92E, 0x11CF, {0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
244static const GUID_T asf_guid_codec_list = {0x86D15240, 0x311D, 0x11D0, {0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
245static const GUID_T asf_guid_content_description = {0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
246static const GUID_T asf_guid_ext_content_description = {0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
247static const GUID_T asf_guid_stream_bitrate_props = {0x7BF875CE, 0x468D, 0x11D1, {0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2}};
248static const GUID_T asf_guid_language_list = {0x7C4346A9, 0xEFE0, 0x4BFC, {0xB2, 0x29, 0x39, 0x3E, 0xDE, 0x41, 0x5C, 0x85}};
249static const GUID_T asf_guid_metadata = {0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}};
250static const GUID_T asf_guid_padding = {0x1806D474, 0xCADF, 0x4509, {0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8}};
251static const GUID_T asf_guid_content_encryption = {0x2211B3FB, 0xBD23, 0x11D2, {0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E}};
252static const GUID_T asf_guid_ext_content_encryption = {0x298AE614, 0x2622, 0x4C17, {0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9C}};
253static const GUID_T asf_guid_adv_content_encryption = {0x43058533, 0x6981, 0x49E6, {0x9B, 0x74, 0xAD, 0x12, 0xCB, 0x86, 0xD5, 0x8C}};
254static const GUID_T asf_guid_compatibility = {0x26F18B5D, 0x4584, 0x47EC, {0x9F, 0x5F, 0x0E, 0x65, 0x1F, 0x04, 0x52, 0xC9}};
255static const GUID_T asf_guid_script_command = {0x1EFB1A30, 0x0B62, 0x11D0, {0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
256static const GUID_T asf_guid_mutual_exclusion = {0xD6E229DC, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
257
258static const GUID_T asf_guid_stream_type_video = {0xBC19EFC0, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
259static const GUID_T asf_guid_stream_type_audio = {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
260
261/******************************************************************************
262List of GUIDs and their associated processing functions
263******************************************************************************/
264static struct {
265 const GUID_T *guid;
266 const char *psz_name;
267 VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T *, int64_t );
268
269} asf_object_list[] =
270{
271 {&asf_guid_header, "header", asf_read_object_header},
272 {&asf_guid_file_props, "file properties", asf_read_object_file_properties},
273 {&asf_guid_stream_props, "stream properties", asf_read_object_stream_properties},
274 {&asf_guid_ext_stream_props, "extended stream properties", asf_read_object_ext_stream_properties},
275 {&asf_guid_data, "data", asf_read_object_data},
276 {&asf_guid_simple_index, "simple index", asf_read_object_simple_index},
277 {&asf_guid_index, "index", asf_read_object_index},
278 {&asf_guid_index_parameters, "index parameters", asf_read_object_index_parameters},
279 {&asf_guid_header_ext, "header extension", asf_read_object_header_ext},
280 {&asf_guid_codec_list, "codec list", asf_read_object_codec_list},
281 {&asf_guid_content_description, "content description", asf_read_object_content_description},
282 {&asf_guid_ext_content_description, "extended content description", asf_skip_unprocessed_object},
283 {&asf_guid_stream_bitrate_props, "stream bitrate properties", asf_read_object_stream_bitrate_props},
284 {&asf_guid_language_list, "language list", asf_skip_unprocessed_object},
285 {&asf_guid_metadata, "metadata", asf_skip_unprocessed_object},
286 {&asf_guid_padding, "padding", asf_skip_unprocessed_object},
287 {&asf_guid_compatibility, "compatibility", asf_skip_unprocessed_object},
288 {&asf_guid_script_command, "script command", asf_skip_unprocessed_object},
289 {&asf_guid_mutual_exclusion, "mutual exclusion", asf_skip_unprocessed_object},
290 {&asf_guid_content_encryption, "content encryption", &asf_read_object_content_encryption},
291 {&asf_guid_ext_content_encryption, "extended content encryption", &asf_read_object_ext_content_encryption},
292 {&asf_guid_adv_content_encryption, "advanced content encryption", &asf_read_object_adv_content_encryption},
293 {0, "unknown", asf_skip_unprocessed_object}
294};
295
296/******************************************************************************
297Local Functions
298******************************************************************************/
299
300/** Find the track associated with an ASF stream id */
301static VC_CONTAINER_TRACK_T *asf_reader_find_track( VC_CONTAINER_T *p_ctx, unsigned int stream_id,
302 bool b_create)
303{
304 VC_CONTAINER_TRACK_T *p_track = 0;
305 VC_CONTAINER_MODULE_T * module = p_ctx->priv->module;
306 unsigned int i;
307
308 /* discard the key-frame flag */
309 stream_id &= 0x7f;
310
311 /* look to see if we have already allocated the stream */
312 i = module->stream_number_to_index[stream_id];
313
314 if(i < p_ctx->tracks_num) /* We found it */
315 p_track = p_ctx->tracks[i];
316
317 if(!p_track && b_create && p_ctx->tracks_num < ASF_TRACKS_MAX)
318 {
319 /* Allocate and initialise a new track */
320 p_ctx->tracks[p_ctx->tracks_num] = p_track =
321 vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
322 if(p_track)
323 {
324 /* store the stream ID */
325 p_track->priv->module->stream_id = stream_id;
326
327 /* Store the translation table value */
328 module->stream_number_to_index[stream_id] = p_ctx->tracks_num;
329
330 /* count the track */
331 p_ctx->tracks_num++;
332 }
333 }
334
335 if(!p_track && b_create)
336 LOG_DEBUG(p_ctx, "could not create track for stream id: %i", stream_id);
337
338 return p_track;
339}
340
341/** Base function used to read an ASF object from the ASF header.
342 * This will read the object header do lots of sanity checking and pass on the rest
343 * of the reading to the object specific reading function */
344static VC_CONTAINER_STATUS_T asf_read_object( VC_CONTAINER_T *p_ctx, int64_t size )
345{
346 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
347 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
348 int64_t object_size, offset = STREAM_POSITION(p_ctx);
349 unsigned int i, unknown_objects = 0, is_data_object;
350 GUID_T guid;
351
352 /* Sanity check the size of the data */
353 if(size && size < ASF_OBJECT_HEADER_SIZE)
354 {
355 LOG_DEBUG(p_ctx, "invalid object header (too small)");
356 return VC_CONTAINER_ERROR_CORRUPTED;
357 }
358
359 if(READ_GUID(p_ctx, &guid, "Object ID") != sizeof(guid))
360 return STREAM_STATUS(p_ctx);
361
362 /* Find out which GUID we are dealing with */
363 for( i = 0; asf_object_list[i].guid; i++ )
364 {
365 if(guid.word0 != asf_object_list[i].guid->word0) continue;
366 if(!memcmp(&guid, asf_object_list[i].guid, sizeof(guid))) break;
367 }
368
369 LOG_FORMAT(p_ctx, "Object Name: %s", asf_object_list[i].psz_name);
370
371 /* Bail out if we find too many consecutive unknown objects */
372 if(!asf_object_list[i].guid) unknown_objects++;
373 else unknown_objects = 0;
374 if(unknown_objects >= ASF_MAX_CONSECUTIVE_UNKNOWN_OBJECTS)
375 {
376 LOG_DEBUG(p_ctx, "too many unknown objects");
377 return VC_CONTAINER_ERROR_CORRUPTED;
378 }
379
380 is_data_object = asf_object_list[i].pf_func == asf_read_object_data;
381
382 object_size = READ_U64(p_ctx, "Object Size");
383
384 /* Sanity check the object size */
385 if(object_size < 0 /* Shouldn't ever get that big */ ||
386 /* Minimum size check (data object can have a size == 0) */
387 (object_size < ASF_OBJECT_HEADER_SIZE && !(is_data_object && !object_size)) ||
388 /* Only the data object can really be massive */
389 (!is_data_object && object_size > ASF_MAX_OBJECT_SIZE))
390 {
391 LOG_DEBUG(p_ctx, "object %s has an invalid size (%"PRIi64")",
392 asf_object_list[i].psz_name, object_size);
393 return VC_CONTAINER_ERROR_CORRUPTED;
394 }
395 if(size && object_size > size)
396 {
397 LOG_DEBUG(p_ctx, "object %s is bigger than it should (%"PRIi64" > %"PRIi64")",
398 asf_object_list[i].psz_name, object_size, size);
399 return VC_CONTAINER_ERROR_CORRUPTED;
400 }
401 size = object_size;
402
403 if(module->object_level >= 2 * ASF_MAX_OBJECT_LEVEL)
404 {
405 LOG_DEBUG(p_ctx, "object %s is too deep. skipping", asf_object_list[i].psz_name);
406 status = asf_skip_unprocessed_object(p_ctx, size - ASF_OBJECT_HEADER_SIZE);
407 /* Just bail out, hoping we have enough data */
408 }
409 else
410 {
411 module->object_level++;
412
413 /* Call the object specific parsing function */
414 status = asf_object_list[i].pf_func(p_ctx, size - ASF_OBJECT_HEADER_SIZE);
415
416 module->object_level--;
417
418 if(status != VC_CONTAINER_SUCCESS)
419 LOG_DEBUG(p_ctx, "object %s appears to be corrupted (%i)", asf_object_list[i].psz_name, status);
420 }
421
422 /* The stream position should be exactly at the end of the object */
423 {
424 int64_t bytes_processed = STREAM_POSITION(p_ctx) - offset;
425
426 /* fail with overruns */
427 if (bytes_processed > size)
428 {
429 /* Things have gone really bad here and we ended up reading past the end of the
430 * object. We could maybe try to be clever and recover by seeking back to the end
431 * of the object. However if we get there, the file is clearly corrupted so there's
432 * no guarantee it would work anyway. */
433 LOG_DEBUG(p_ctx, "%"PRIi64" bytes overrun past the end of object %s",
434 bytes_processed-size, asf_object_list[i].psz_name);
435 return VC_CONTAINER_ERROR_CORRUPTED;
436 }
437
438 /* Handle underruns by throwing away the data (this should never happen, but we don't really care if it does) */
439 if (bytes_processed < size)
440 {
441 size -= bytes_processed;
442 LOG_DEBUG(p_ctx, "%"PRIi64" bytes left unread in object %s", size, asf_object_list[i].psz_name);
443
444 if(size < ASF_MAX_OBJECT_SIZE)
445 SKIP_BYTES(p_ctx, size); /* read a small amount */
446 else
447 SEEK(p_ctx, STREAM_POSITION(p_ctx) + size); /* seek a large distance */
448 }
449 }
450
451 return STREAM_STATUS(p_ctx);
452}
453
454/** Reads an ASF header object */
455static VC_CONTAINER_STATUS_T asf_read_object_header( VC_CONTAINER_T *p_ctx, int64_t size )
456{
457 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
458 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
459 int64_t offset = STREAM_POSITION(p_ctx);
460
461 /* Sanity check the size of the data */
462 if((size -= 6) < 0) return VC_CONTAINER_ERROR_CORRUPTED;
463
464 SKIP_U32(p_ctx, "Number of Header Objects"); /* FIXME: could use that */
465 SKIP_U8(p_ctx, "Reserved1");
466 SKIP_U8(p_ctx, "Reserved2");
467
468 /* Read contained objects */
469 module->object_level++;
470 while(status == VC_CONTAINER_SUCCESS && size >= ASF_OBJECT_HEADER_SIZE)
471 {
472 offset = STREAM_POSITION(p_ctx);
473 status = asf_read_object(p_ctx, size);
474 size -= (STREAM_POSITION(p_ctx) - offset);
475 }
476 module->object_level--;
477
478 return status;
479}
480
481/** Reads an ASF extended header object */
482static VC_CONTAINER_STATUS_T asf_read_object_header_ext( VC_CONTAINER_T *p_ctx, int64_t size )
483{
484 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
485 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
486 int64_t data_size, offset;
487
488 ASF_SKIP_GUID(p_ctx, size, "Reserved Field 1");
489 ASF_SKIP_U16(p_ctx, size, "Reserved Field 2");
490 data_size = ASF_READ_U32(p_ctx, size, "Header Extension Data Size");
491
492 if(data_size != size)
493 LOG_DEBUG(p_ctx, "invalid header extension data size (%"PRIi64",%"PRIi64")", data_size, size);
494
495 CHECK_POINT(p_ctx, size);
496
497 /* Read contained objects */
498 module->object_level++;
499 while(status == VC_CONTAINER_SUCCESS && size >= ASF_OBJECT_HEADER_SIZE)
500 {
501 offset = STREAM_POSITION(p_ctx);
502 status = asf_read_object(p_ctx, size);
503 size -= (STREAM_POSITION(p_ctx) - offset);
504 }
505 module->object_level--;
506
507 return status;
508}
509
510/** Reads an ASF file properties object */
511static VC_CONTAINER_STATUS_T asf_read_object_file_properties( VC_CONTAINER_T *p_ctx, int64_t size )
512{
513 uint32_t max_packet_size;
514 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
515
516 ASF_SKIP_GUID(p_ctx, size, "File ID");
517 ASF_SKIP_U64(p_ctx, size, "File Size");
518 ASF_SKIP_U64(p_ctx, size, "Creation Date");
519 ASF_SKIP_U64(p_ctx, size, "Data Packets Count");
520 module->duration = ASF_READ_U64(p_ctx, size, "Play Duration") / UINT64_C(10); /* read in 100nS units, stored in uS */
521 ASF_SKIP_U64(p_ctx, size, "Send Duration");
522 module->preroll = ASF_READ_U64(p_ctx, size, "Preroll") * UINT64_C(1000); /* read in mS, storedin uS */
523 module->broadcast = ASF_READ_U32(p_ctx, size, "Flags") & 0x1;
524 module->packet_size = ASF_READ_U32(p_ctx, size, "Minimum Data Packet Size");
525 max_packet_size = ASF_READ_U32(p_ctx, size, "Maximum Data Packet Size");
526 ASF_SKIP_U32(p_ctx, size, "Maximum Bitrate");
527
528 if(module->preroll < module->duration) module->duration -= module->preroll;
529 else module->duration = 0;
530
531 /* Sanity check the packet size */
532 if(!module->packet_size)
533 {
534 LOG_DEBUG(p_ctx, "packet size cannot be 0");
535 return VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED;
536 }
537
538 if(max_packet_size != module->packet_size)
539 {
540 LOG_DEBUG(p_ctx, "asf stream not supported (min packet size: %i != max packet size: %i)",
541 module->packet_size, max_packet_size);
542 return VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED;
543 }
544
545 return STREAM_STATUS(p_ctx);
546}
547
548/** Reads the bitmapinfoheader structure contained in a stream properties object */
549static VC_CONTAINER_STATUS_T asf_read_bitmapinfoheader( VC_CONTAINER_T *p_ctx,
550 VC_CONTAINER_TRACK_T *p_track, int64_t size )
551{
552 uint32_t bmih_size, formatdata_size;
553 uint32_t fourcc;
554
555 /* Sanity check the size of the data */
556 if(size < 40 + 11) return VC_CONTAINER_ERROR_CORRUPTED;
557
558 /* Read the preamble to the BITMAPINFOHEADER */
559 ASF_SKIP_U32(p_ctx, size, "Encoded Image Width");
560 ASF_SKIP_U32(p_ctx, size, "Encoded Image Height");
561 ASF_SKIP_U8(p_ctx, size, "Reserved Flags");
562 formatdata_size = ASF_READ_U16(p_ctx, size, "Format Data Size");
563
564 /* Sanity check the size of the data */
565 if(formatdata_size < 40 || size < formatdata_size) return VC_CONTAINER_ERROR_CORRUPTED;
566 bmih_size = ASF_READ_U32(p_ctx, size, "Format Data Size");
567 if(bmih_size < 40 || bmih_size > formatdata_size) return VC_CONTAINER_ERROR_CORRUPTED;
568
569 /* Read BITMAPINFOHEADER structure */
570 p_track->format->type->video.width = ASF_READ_U32(p_ctx, size, "Image Width");
571 p_track->format->type->video.height = ASF_READ_U32(p_ctx, size, "Image Height"); /* Signed */
572 ASF_SKIP_U16(p_ctx, size, "Reserved");
573 ASF_SKIP_U16(p_ctx, size, "Bits Per Pixel Count");
574 ASF_READ_BYTES(p_ctx, size, (char *)&fourcc, 4); /* Compression ID */
575 LOG_FORMAT(p_ctx, "Compression ID: %4.4s", (char *)&fourcc);
576 p_track->format->codec = vfw_fourcc_to_codec(fourcc);
577 if(p_track->format->codec == VC_CONTAINER_CODEC_UNKNOWN)
578 p_track->format->codec = fourcc;
579 ASF_SKIP_U32(p_ctx, size, "Image Size");
580 ASF_SKIP_U32(p_ctx, size, "Horizontal Pixels Per Meter");
581 ASF_SKIP_U32(p_ctx, size, "Vertical Pixels Per Meter");
582 ASF_SKIP_U32(p_ctx, size, "Colors Used Count");
583 ASF_SKIP_U32(p_ctx, size, "Important Colors Count");
584
585 if(!(bmih_size -= 40))return VC_CONTAINER_SUCCESS;
586
587 if(bmih_size > ASF_EXTRADATA_MAX)
588 {
589 LOG_DEBUG(p_ctx, "extradata truncated");
590 bmih_size = ASF_EXTRADATA_MAX;
591 }
592 p_track->format->extradata = p_track->priv->module->extradata;
593 p_track->format->extradata_size = ASF_READ_BYTES(p_ctx, size, p_track->format->extradata, bmih_size);
594
595 return STREAM_STATUS(p_ctx);
596}
597
598/** Reads the waveformatex structure contained in a stream properties object */
599static VC_CONTAINER_STATUS_T asf_read_waveformatex( VC_CONTAINER_T *p_ctx,
600 VC_CONTAINER_TRACK_T *p_track, int64_t size)
601{
602 uint16_t extradata_size;
603
604 /* Read WAVEFORMATEX structure */
605 p_track->format->codec = waveformat_to_codec(ASF_READ_U16(p_ctx, size, "Codec ID"));
606 p_track->format->type->audio.channels = ASF_READ_U16(p_ctx, size, "Number of Channels");
607 p_track->format->type->audio.sample_rate = ASF_READ_U32(p_ctx, size, "Samples per Second");
608 p_track->format->bitrate = ASF_READ_U32(p_ctx, size, "Average Number of Bytes Per Second") * 8;
609 p_track->format->type->audio.block_align = ASF_READ_U16(p_ctx, size, "Block Alignment");
610 p_track->format->type->audio.bits_per_sample = ASF_READ_U16(p_ctx, size, "Bits Per Sample");
611 extradata_size = ASF_READ_U16(p_ctx, size, "Codec Specific Data Size");
612
613 CHECK_POINT(p_ctx, size);
614
615 if(!extradata_size) return VC_CONTAINER_SUCCESS;
616
617 /* Sanity check the size of the data */
618 if(extradata_size > size) return VC_CONTAINER_ERROR_CORRUPTED;
619
620 if(extradata_size > ASF_EXTRADATA_MAX)
621 {
622 LOG_DEBUG(p_ctx, "extradata truncated");
623 extradata_size = ASF_EXTRADATA_MAX;
624 }
625 p_track->format->extradata = p_track->priv->module->extradata;
626 p_track->format->extradata_size = ASF_READ_BYTES(p_ctx, size, p_track->format->extradata, extradata_size);
627
628 return STREAM_STATUS(p_ctx);
629}
630
631/** Reads an ASF stream properties object */
632static VC_CONTAINER_STATUS_T asf_read_object_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size )
633{
634 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
635 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
636 VC_CONTAINER_TRACK_T *p_track;
637 unsigned int ts_length, flags;
638 VC_CONTAINER_ES_TYPE_T type = VC_CONTAINER_ES_TYPE_UNKNOWN;
639 GUID_T stream_type;
640 int64_t offset;
641
642 ASF_READ_GUID(p_ctx, size, &stream_type, "Stream Type");
643 ASF_SKIP_GUID(p_ctx, size, "Error Correction Type");
644
645 /* The time_offset field is in 100nS units. Scale back to uS */
646 module->time_offset = ASF_READ_U64(p_ctx, size, "Time Offset") / UINT64_C(10);
647 ts_length = ASF_READ_U32(p_ctx, size, "Type-Specific Data Length");
648 ASF_SKIP_U32(p_ctx, size, "Error Correction Data Length");
649 flags = ASF_READ_U16(p_ctx, size, "Flags");
650 ASF_SKIP_U32(p_ctx, size, "Reserved");
651
652 CHECK_POINT(p_ctx, size);
653
654 /* Zero is not a valid stream id */
655 if(!(flags & 0x7F)) goto skip;
656
657 if(!memcmp(&stream_type, &asf_guid_stream_type_video, sizeof(GUID_T)))
658 type = VC_CONTAINER_ES_TYPE_VIDEO;
659 else if(!memcmp(&stream_type, &asf_guid_stream_type_audio, sizeof(GUID_T)))
660 type = VC_CONTAINER_ES_TYPE_AUDIO;
661
662 /* Check we know what to do with this track */
663 if(type == VC_CONTAINER_ES_TYPE_UNKNOWN) goto skip;
664
665 /* Sanity check sizes */
666 if(ts_length > size) return VC_CONTAINER_ERROR_CORRUPTED;
667
668 p_track = asf_reader_find_track( p_ctx, flags, true);
669 if(!p_track) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
670
671 p_track->format->es_type = type;
672
673 offset = STREAM_POSITION(p_ctx);
674 if(type == VC_CONTAINER_ES_TYPE_AUDIO)
675 status = asf_read_waveformatex(p_ctx, p_track, (int64_t)ts_length);
676 else if(type == VC_CONTAINER_ES_TYPE_VIDEO)
677 status = asf_read_bitmapinfoheader(p_ctx, p_track, (int64_t)ts_length);
678 size -= STREAM_POSITION(p_ctx) - offset;
679
680 if(status) return status;
681
682 p_track->priv->module->b_valid = true;
683 p_track->is_enabled = true;
684 p_track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
685
686 /* Codec specific work-arounds */
687 switch(p_track->format->codec)
688 {
689 case VC_CONTAINER_CODEC_MPGA:
690 /* Can't guarantee that the data is framed */
691 p_track->format->flags &= ~VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
692 break;
693 default: break;
694 }
695
696 skip:
697 if(size) SKIP_BYTES(p_ctx, size);
698 return STREAM_STATUS(p_ctx);
699}
700
701/** Reads an ASF extended stream properties object */
702static VC_CONTAINER_STATUS_T asf_read_object_ext_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size )
703{
704 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
705 VC_CONTAINER_TRACK_T *p_track;
706 unsigned int i, name_count, pes_count, length, stream_id;
707
708 ASF_SKIP_U64(p_ctx, size, "Start Time");
709 ASF_SKIP_U64(p_ctx, size, "End Time");
710 ASF_SKIP_U32(p_ctx, size, "Data Bitrate");
711 ASF_SKIP_U32(p_ctx, size, "Buffer Size");
712 ASF_SKIP_U32(p_ctx, size, "Initial Buffer Fullness");
713 ASF_SKIP_U32(p_ctx, size, "Alternate Data Bitrate");
714 ASF_SKIP_U32(p_ctx, size, "Alternate Buffer Size");
715 ASF_SKIP_U32(p_ctx, size, "Alternate Initial Buffer Fullness");
716 ASF_SKIP_U32(p_ctx, size, "Maximum Object Size");
717 ASF_SKIP_U32(p_ctx, size, "Flags");
718 stream_id = ASF_READ_U16(p_ctx, size, "Stream Number");
719 ASF_SKIP_U16(p_ctx, size, "Stream Language ID Index");
720 ASF_SKIP_U64(p_ctx, size, "Average Time Per Frame");
721 name_count = ASF_READ_U16(p_ctx, size, "Stream Name Count");
722 pes_count = ASF_READ_U16(p_ctx, size, "Payload Extension System Count");
723
724 CHECK_POINT(p_ctx, size);
725
726 p_track = asf_reader_find_track( p_ctx, stream_id, true);
727 if(!p_track) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
728
729 /* Stream Names */
730 for(i = 0; i < name_count; i++)
731 {
732 if(size < 4) return VC_CONTAINER_ERROR_CORRUPTED;
733 ASF_SKIP_U16(p_ctx, size, "Language ID Index");
734 length = ASF_READ_U16(p_ctx, size, "Stream Name Length");
735 if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
736 ASF_SKIP_BYTES(p_ctx, size, length); /* Stream Name */
737 }
738
739 CHECK_POINT(p_ctx, size);
740
741 /* Payload Extension Systems */
742 for(i = 0; i < pes_count; i++)
743 {
744 if(size < 22) return VC_CONTAINER_ERROR_CORRUPTED;
745 ASF_SKIP_GUID(p_ctx, size, "Extension System ID");
746 ASF_SKIP_U16(p_ctx, size, "Extension Data Size");
747 length = ASF_READ_U32(p_ctx, size, "Extension System Info Length");
748 if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
749 ASF_SKIP_BYTES(p_ctx, size, length); /* Extension System Info */
750 }
751
752 CHECK_POINT(p_ctx, size);
753
754 /* Optional Stream Properties Object */
755 if(size >= ASF_OBJECT_HEADER_SIZE)
756 status = asf_read_object(p_ctx, size);
757
758 return status;
759}
760
761/** Reads an ASF simple index object */
762static VC_CONTAINER_STATUS_T asf_read_object_simple_index( VC_CONTAINER_T *p_ctx, int64_t size )
763{
764 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
765 VC_CONTAINER_TRACK_MODULE_T *track_module = 0;
766 uint64_t time_interval, index_duration;
767 uint32_t count;
768 unsigned int i;
769
770 ASF_SKIP_GUID(p_ctx, size, "File ID");
771
772 /* time in 100nS units, converted to uS */
773 time_interval = ASF_READ_U64(p_ctx, size, "Index Entry Time Interval") / UINT64_C(10);
774 ASF_SKIP_U32(p_ctx, size, "Maximum Packet Count");
775 count = ASF_READ_U32(p_ctx, size, "Index Entries Count");
776
777 CHECK_POINT(p_ctx, size);
778
779 if(count > size / 6)
780 {
781 LOG_DEBUG(p_ctx, "invalid number of entries in the index (%i, %"PRIi64")", count, size / 6);
782 count = (uint32_t)(size / 6);
783 }
784
785 /* Find the track corresponding to this index */
786 for(i = 0; i < p_ctx->tracks_num; i++)
787 {
788 if(p_ctx->tracks[i]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO) continue;
789 if(p_ctx->tracks[i]->priv->module->simple_index.offset) continue;
790 break;
791 }
792
793 /* Skip the index if we can't find the associated track */
794 if(i == p_ctx->tracks_num || !count || !time_interval) return VC_CONTAINER_SUCCESS;
795 track_module = p_ctx->tracks[i]->priv->module;
796
797 track_module->simple_index.offset = STREAM_POSITION(p_ctx);
798 track_module->simple_index.time_interval = time_interval;
799 track_module->simple_index.num_entries = count;
800
801 /* Check that the index covers the whole duration of the stream */
802 index_duration = (count * time_interval);
803 if(module->preroll + module->time_offset < index_duration)
804 index_duration -= module->preroll + module->time_offset;
805 else
806 index_duration = 0;
807
808 if((uint64_t)module->duration > index_duration + time_interval)
809 {
810 track_module->simple_index.incomplete = true;
811 }
812
813 LOG_DEBUG(p_ctx, "index covers %fS on %fS",
814 (float)index_duration / 1E6, (float)module->duration / 1E6);
815
816#if defined(ENABLE_CONTAINERS_LOG_FORMAT) && defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
817 for(i = 0; i < count; i++)
818 {
819 LOG_FORMAT(p_ctx, "Entry: %u", i);
820 ASF_SKIP_U32(p_ctx, size, "Packet Number");
821 ASF_SKIP_U16(p_ctx, size, "Packet Count");
822 if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) break;
823 }
824 size = i * 6;
825#else
826 size = CACHE_BYTES(p_ctx, count * 6);
827#endif
828
829 /* Check that the index is complete */
830 if(size / 6 != count )
831 {
832 LOG_DEBUG(p_ctx, "index is incomplete (%i entries on %i)", (int)size / 6, count);
833 track_module->simple_index.num_entries = (uint32_t)(size / 6);
834 track_module->simple_index.incomplete = true;
835 }
836
837 /* If we haven't had an index before, or this track is enabled, we'll store this one.
838 * (Usually there will only be one video track, and it will be enabled, so both tests
839 * will pass. This check is an attempt to handle content not structured as it should be) */
840 if ((!module->simple_index_track) || (p_ctx->tracks[i]->is_enabled))
841 {
842 /* Save the track so we don't have to look for it in when seeking */
843 module->simple_index_track = track_module;
844 }
845
846 return STREAM_STATUS(p_ctx);
847}
848
849/** Reads an ASF index object */
850static VC_CONTAINER_STATUS_T asf_read_object_index( VC_CONTAINER_T *p_ctx, int64_t size )
851{
852 uint32_t i, specifiers_count, blocks_count;
853 uint32_t best_specifier_type[ASF_TRACKS_MAX] = {0};
854
855 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
856
857 /* Read the time interval and scale to microseconds */
858 module->top_level_index.entry_time_interval
859 = (uint64_t)ASF_READ_U32(p_ctx, size, "Index Entry Time Interval") * INT64_C(1000);
860
861 module->top_level_index.specifiers_count
862 = specifiers_count
863 = (uint32_t)ASF_READ_U16(p_ctx, size, "Index Specifiers Count");
864
865 module->top_level_index.block_count
866 = blocks_count
867 = ASF_READ_U32(p_ctx, size, "Index Blocks Count");
868
869 CHECK_POINT(p_ctx, size);
870
871 /* Index specifiers. Search for the one we like best */
872 if(size < specifiers_count * 4) return VC_CONTAINER_ERROR_CORRUPTED;
873 for(i = 0; i < specifiers_count; i++)
874 {
875 uint32_t stream_id = (uint32_t)ASF_READ_U16(p_ctx, size, "Stream Number");
876 uint32_t index_type = (uint32_t)ASF_READ_U16(p_ctx, size, "Index Type");
877
878 /* Find the track index for this stream */
879 unsigned track = module->stream_number_to_index[stream_id];
880
881 if ((track < ASF_TRACKS_MAX) &&
882 (index_type > best_specifier_type[track]))
883 {
884 /* We like this better than any we have seen before. Note - if we don't like any
885 * the file must be subtly corrupt - best we say nothing, and attempt a seek with
886 * the data for the first specifier, it will be better than nothing. At worst it
887 * will play until a seek is attempted */
888 module->top_level_index.active_specifiers[track] = i;
889 best_specifier_type[track] = index_type;
890 }
891 }
892
893 for (i = 0; i < p_ctx->tracks_num; i++)
894 {
895 LOG_DEBUG(p_ctx, "indexing track %"PRIu32" with specifier %"PRIu32,
896 i, module->top_level_index.active_specifiers[i]);
897 }
898
899 CHECK_POINT(p_ctx, size);
900
901 /* The blocks start here */
902 module->top_level_index.blocks_offset = STREAM_POSITION(p_ctx);
903
904 /* Index blocks */
905#if !(defined(ENABLE_CONTAINERS_LOG_FORMAT) && defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE))
906 blocks_count = 0; /* Don't log the index. Note we'll get a warning on unprocessed data */
907#endif
908 /* coverity[dead_error_condition] Code needs to stay there for debugging purposes */
909 for(i = 0; i < blocks_count; i++)
910 {
911 uint32_t j, k, count = ASF_READ_U32(p_ctx, size, "Index Entry Count");
912
913 for(j = 0; j < specifiers_count; j++)
914 {
915 ASF_SKIP_U64(p_ctx, size, "Block Positions");
916 }
917 for(j = 0; j < count; j++)
918 {
919 for(k = 0; k < specifiers_count; k++)
920 {
921 ASF_SKIP_U32(p_ctx, size, "Offsets");
922 }
923 }
924 }
925
926 return STREAM_STATUS(p_ctx);
927}
928
929/** Reads an ASF index parameters object */
930static VC_CONTAINER_STATUS_T asf_read_object_index_parameters( VC_CONTAINER_T *p_ctx, int64_t size )
931{
932#ifdef ENABLE_CONTAINERS_LOG_FORMAT
933 /* This is added for debugging only. The spec (section 4.9) states that this is also enclosed in
934 * the index object (see above) and that they are identical. I think they aren't always... */
935 uint32_t i, specifiers_count;
936
937 /* Read the time interval in milliseconds */
938 ASF_SKIP_U32(p_ctx, size, "Index Entry Time Interval");
939
940 specifiers_count = (uint32_t)ASF_READ_U16(p_ctx, size, "Index Specifiers Count");
941
942 CHECK_POINT(p_ctx, size);
943
944 /* Index specifiers. Search for the one we like best */
945 if(size < specifiers_count * 4) return VC_CONTAINER_ERROR_CORRUPTED;
946 for(i = 0; i < specifiers_count; i++)
947 {
948 ASF_SKIP_U16(p_ctx, size, "Stream Number");
949 ASF_SKIP_U16(p_ctx, size, "Index Type");
950 }
951#endif
952 CHECK_POINT(p_ctx, size);
953
954 return STREAM_STATUS(p_ctx);
955}
956
957/** Reads an ASF codec list object */
958static VC_CONTAINER_STATUS_T asf_read_object_codec_list( VC_CONTAINER_T *p_ctx, int64_t size )
959{
960 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
961 uint32_t i, count, length;
962
963 ASF_SKIP_GUID(p_ctx, size, "Reserved");
964 count = ASF_READ_U32(p_ctx, size, "Codec Entries Count");
965
966 CHECK_POINT(p_ctx, size);
967
968 /* Codec entries */
969 for(i = 0; i < count; i++)
970 {
971 ASF_SKIP_U16(p_ctx, size, "Type");
972 length = ASF_READ_U16(p_ctx, size, "Codec Name Length");
973 if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
974 ASF_SKIP_STRING(p_ctx, size, length * 2, "Codec Name");
975 length = ASF_READ_U16(p_ctx, size, "Codec Description Length");
976 if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
977 ASF_SKIP_STRING(p_ctx, size, length * 2, "Codec Description");
978 length = ASF_READ_U16(p_ctx, size, "Codec Information Length");
979 if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
980 ASF_SKIP_BYTES(p_ctx, size, length);
981
982 CHECK_POINT(p_ctx, size);
983 }
984
985 return status;
986}
987
988/** Reads an ASF content description object */
989static VC_CONTAINER_STATUS_T asf_read_object_content_description( VC_CONTAINER_T *p_ctx, int64_t size )
990{
991 uint16_t t_length, a_length, c_length, d_length, r_length;
992
993 t_length = ASF_READ_U16(p_ctx, size, "Title Length");
994 a_length = ASF_READ_U16(p_ctx, size, "Author Length");
995 c_length = ASF_READ_U16(p_ctx, size, "Copyright Length");
996 d_length = ASF_READ_U16(p_ctx, size, "Description Length");
997 r_length = ASF_READ_U16(p_ctx, size, "Rating Length");
998
999 CHECK_POINT(p_ctx, size);
1000
1001 if(size < t_length) return VC_CONTAINER_ERROR_CORRUPTED;
1002 ASF_SKIP_STRING(p_ctx, size, t_length, "Title");
1003 if(size < a_length) return VC_CONTAINER_ERROR_CORRUPTED;
1004 ASF_SKIP_STRING(p_ctx, size, a_length, "Author");
1005 if(size < c_length) return VC_CONTAINER_ERROR_CORRUPTED;
1006 ASF_SKIP_STRING(p_ctx, size, c_length, "Copyright");
1007 if(size < d_length) return VC_CONTAINER_ERROR_CORRUPTED;
1008 ASF_SKIP_STRING(p_ctx, size, d_length, "Description");
1009 if(size < r_length) return VC_CONTAINER_ERROR_CORRUPTED;
1010 ASF_SKIP_STRING(p_ctx, size, r_length, "Rating");
1011
1012 return STREAM_STATUS(p_ctx);
1013}
1014
1015/** Reads an ASF stream bitrate properties object */
1016static VC_CONTAINER_STATUS_T asf_read_object_stream_bitrate_props( VC_CONTAINER_T *p_ctx, int64_t size )
1017{
1018 uint16_t i, count;
1019
1020 count = ASF_READ_U16(p_ctx, size, "Bitrate Records Count");
1021
1022 /* Bitrate records */
1023 if(size < count * 6) return VC_CONTAINER_ERROR_CORRUPTED;
1024 for(i = 0; i < count; i++)
1025 {
1026 ASF_SKIP_U16(p_ctx, size, "Flags");
1027 ASF_SKIP_U32(p_ctx, size, "Average Bitrate");
1028 }
1029
1030 return STREAM_STATUS(p_ctx);
1031}
1032
1033/** Reads an ASF content encryption object */
1034static VC_CONTAINER_STATUS_T asf_read_object_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size )
1035{
1036 uint32_t length;
1037
1038 length = ASF_READ_U32(p_ctx, size, "Secret Data Length");
1039 ASF_SKIP_BYTES(p_ctx, size, length);
1040
1041 length = ASF_READ_U32(p_ctx, size, "Protection Type Length");
1042 ASF_SKIP_BYTES(p_ctx, size, length);
1043
1044 length = ASF_READ_U32(p_ctx, size, "Key ID Length");
1045 ASF_SKIP_BYTES(p_ctx, size, length);
1046
1047 length = ASF_READ_U32(p_ctx, size, "License URL Length");
1048 ASF_SKIP_BYTES(p_ctx, size, length); /* null-terminated ASCII string */
1049
1050 return STREAM_STATUS(p_ctx);
1051}
1052
1053/** Reads an ASF extended content encryption object */
1054static VC_CONTAINER_STATUS_T asf_read_object_ext_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size )
1055{
1056 uint32_t length;
1057
1058 length = ASF_READ_U32(p_ctx, size, "Data Size");
1059 ASF_SKIP_BYTES(p_ctx, size, length);
1060
1061 return STREAM_STATUS(p_ctx);
1062}
1063
1064/** Reads an ASF advanced content encryption object */
1065static VC_CONTAINER_STATUS_T asf_read_object_adv_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size )
1066{
1067 uint32_t i, count;
1068
1069 count = ASF_READ_U16(p_ctx, size, "Content Encryption Records Count");
1070
1071 for(i = 0; i < count; i++)
1072 {
1073 uint32_t j, rec_count, data_size, length;
1074
1075 ASF_SKIP_GUID(p_ctx, size, "System ID");
1076 ASF_SKIP_U32(p_ctx, size, "System Version");
1077 rec_count = ASF_READ_U16(p_ctx, size, "Encrypted Object Record Count");
1078
1079 CHECK_POINT(p_ctx, size);
1080
1081 for(j = 0; j < rec_count; j++)
1082 {
1083 ASF_SKIP_U16(p_ctx, size, "Encrypted Object ID Type");
1084 length = ASF_READ_U16(p_ctx, size, "Encrypted Object ID Length");
1085 if(length > size) return VC_CONTAINER_ERROR_CORRUPTED;
1086 ASF_SKIP_BYTES(p_ctx, size, length);
1087 CHECK_POINT(p_ctx, size);
1088 }
1089
1090 data_size = ASF_READ_U32(p_ctx, size, "Data Size");
1091 if(data_size > size) return VC_CONTAINER_ERROR_CORRUPTED;
1092 ASF_SKIP_BYTES(p_ctx, size, data_size);
1093 CHECK_POINT(p_ctx, size);
1094 }
1095
1096 return STREAM_STATUS(p_ctx);
1097}
1098
1099/** Skips over an object that is if a type we don't handle, or is nested too deep */
1100static VC_CONTAINER_STATUS_T asf_skip_unprocessed_object( VC_CONTAINER_T *p_ctx, int64_t size )
1101{
1102 LOG_DEBUG(p_ctx, "%"PRIi64" bytes ignored in unhandled object", size);
1103
1104 if(size < ASF_MAX_OBJECT_SIZE)
1105 SKIP_BYTES(p_ctx, size); /* read a small amount */
1106 else
1107 SEEK(p_ctx, STREAM_POSITION(p_ctx) + size); /* seek a large distance */
1108
1109 return STREAM_STATUS(p_ctx);
1110}
1111
1112/*****************************************************************************/
1113static VC_CONTAINER_STATUS_T asf_find_packet_header( VC_CONTAINER_T *p_ctx,
1114 ASF_PACKET_STATE *p_state )
1115{
1116 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1117 unsigned int search_size = 64*1024; /* should be max packet size according to spec */
1118#ifdef ENABLE_CONTAINER_LOG_DEBUG
1119 uint64_t offset = STREAM_POSITION(p_ctx);
1120#endif
1121 uint8_t h[3];
1122 VC_CONTAINER_PARAM_UNUSED(p_state);
1123
1124 /* Limit the search up to what should theoretically be the packet boundary */
1125 if(module->packet_size)
1126 search_size = module->packet_size -
1127 (STREAM_POSITION(p_ctx) - module->data_offset) % module->packet_size;
1128
1129 for(; search_size > sizeof(h); search_size--)
1130 {
1131 if(PEEK_BYTES(p_ctx, h, sizeof(h)) != sizeof(h))
1132 return STREAM_STATUS(p_ctx);
1133
1134 if(!h[0] && !h[1] && h[2] == 0x82)
1135 {
1136 search_size = 2;
1137 break; /* Got it */
1138 }
1139
1140 SKIP_BYTES(p_ctx, 1);
1141 }
1142
1143 /* If we failed, we just skip to the theoretical packet boundary */
1144 SKIP_BYTES(p_ctx, search_size);
1145
1146 LOG_DEBUG(p_ctx, "found potential sync, discarded %"PRIu64" bytes)",
1147 STREAM_POSITION(p_ctx) - offset);
1148 return VC_CONTAINER_SUCCESS;
1149}
1150
1151/*****************************************************************************/
1152static VC_CONTAINER_STATUS_T asf_read_packet_header( VC_CONTAINER_T *p_ctx,
1153 ASF_PACKET_STATE *p_state, uint64_t size )
1154{
1155 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1156 uint64_t offset = STREAM_POSITION(p_ctx);
1157 uint8_t flags, property_flags, length;
1158 VC_CONTAINER_PARAM_UNUSED(size);
1159
1160 p_state->start = offset;
1161
1162 LOG_FORMAT(p_ctx, "Packet Offset: %"PRIu64, offset);
1163
1164 if ((module->data_size > 0) && (offset >= (module->data_size + module->data_offset)))
1165 {
1166 return VC_CONTAINER_ERROR_EOS;
1167 }
1168
1169 /* Find out whether we are dealing with error correction data or payload parsing info */
1170 if( PEEK_U8(p_ctx) >> 7 )
1171 {
1172 /* We have error correction data */
1173 flags = READ_U8(p_ctx, "Error Correction Flags");
1174 length = flags & 0xF;
1175 SKIP_BYTES(p_ctx, length); /* Error correction data */
1176 }
1177
1178 /* Payload parsing information */
1179 flags = READ_U8(p_ctx, "Length Type Flags");
1180 p_state->multiple_payloads = flags & 1;
1181 property_flags = READ_U8(p_ctx, "Property Flags");
1182 p_state->replicated_data_lt = (property_flags >> 0) & 0x3;
1183 p_state->offset_into_media_object_lt = (property_flags >> 2) & 0x3;
1184 p_state->media_object_number_lt = (property_flags >> 4) & 0x3;
1185
1186 /* Sanity check stream number length type */
1187 if(((property_flags >> 6) & 0x3) != 1)
1188 goto error;
1189
1190 /* If there's no packet size field we default to the size in the file header. */
1191 p_state->size = READ_VLC(p_ctx, (flags >> 5) & 0x3 /* Packet length type */,
1192 module->packet_size, "Packet Length");
1193
1194 READ_VLC(p_ctx, (flags>>1)&0x3 /* Sequence type */, 0, "Sequence");
1195 p_state->padding_size = READ_VLC(p_ctx, (flags>>3)&0x3 /* Padding length type */, 0, "Padding Length");
1196 p_state->send_time = READ_U32(p_ctx, "Send Time") * UINT64_C(1000); /* Read in millisecond units, stored in uS */
1197 SKIP_U16(p_ctx, "Duration"); /* in milliseconds */
1198
1199 p_state->num_payloads = 1;
1200 p_state->current_payload = 0;
1201 if(p_state->multiple_payloads)
1202 {
1203 LOG_FORMAT(p_ctx, "Multiple Payloads");
1204 flags = READ_U8(p_ctx, "Payload Flags");
1205 p_state->num_payloads = flags & 0x3F;
1206 LOG_FORMAT(p_ctx, "Number of Payloads: %i", p_state->num_payloads);
1207 p_state->payload_lt = (flags >> 6) & 3;
1208
1209 /* Sanity check */
1210 if(!p_state->num_payloads) goto error;
1211 }
1212
1213 /* Update the current offset in the packet. */
1214 p_state->current_offset = STREAM_POSITION(p_ctx) - offset;
1215
1216 /* Sanity check offset */
1217 if(p_state->current_offset > p_state->size) goto error;
1218
1219 /* Sanity check padding size */
1220 if(p_state->padding_size + p_state->current_offset > p_state->size) goto error;
1221
1222 /* Sanity check packet size */
1223 if(!module->broadcast &&
1224 (p_state->size != module->packet_size)) goto error;
1225
1226 return STREAM_STATUS(p_ctx);
1227
1228 error:
1229 LOG_FORMAT(p_ctx, "Invalid payload parsing information (offset %"PRIu64")", STREAM_POSITION(p_ctx));
1230 return STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS ?
1231 VC_CONTAINER_ERROR_CORRUPTED : STREAM_STATUS(p_ctx);
1232}
1233
1234/*****************************************************************************/
1235static VC_CONTAINER_STATUS_T asf_read_payload_header( VC_CONTAINER_T *p_ctx,
1236 ASF_PACKET_STATE *p_state /* uint64_t size */ )
1237{
1238 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1239 uint32_t rep_data_length;
1240
1241 if(p_state->current_payload >= p_state->num_payloads)
1242 return VC_CONTAINER_ERROR_CORRUPTED;
1243
1244 p_state->stream_num = READ_U8(p_ctx, "Stream Number");
1245 if(!(p_state->stream_num & 0x7F)) return VC_CONTAINER_ERROR_CORRUPTED;
1246
1247 p_state->media_object_num = READ_VLC(p_ctx, p_state->media_object_number_lt, 0, "Media Object Number");
1248
1249 /* For a compressed packet this field is a timestamp, and is moved to p_state->media_object_pts later */
1250 p_state->media_object_off = READ_VLC(p_ctx, p_state->offset_into_media_object_lt, 0, "Offset Into Media Object");
1251 rep_data_length = READ_VLC(p_ctx, p_state->replicated_data_lt, 0, "Replicated Data Length");
1252
1253 /* Sanity check the replicated data length */
1254 if(rep_data_length && rep_data_length != 1 &&
1255 (rep_data_length < 8 ||
1256 STREAM_POSITION(p_ctx) - p_state->start + p_state->padding_size + rep_data_length > p_state->size))
1257 {
1258 LOG_FORMAT(p_ctx, "invalid replicated data length");
1259 return VC_CONTAINER_ERROR_CORRUPTED;
1260 }
1261
1262 /* Read what we need from the replicated data */
1263 if(rep_data_length > 1)
1264 {
1265 p_state->media_object_size = READ_U32(p_ctx, "Media Object Size");
1266 p_state->media_object_pts = READ_U32(p_ctx, "Presentation Time") * UINT64_C(1000);
1267 p_state->compressed_payloads = 0;
1268 SKIP_BYTES(p_ctx, rep_data_length - 8); /* Rest of replicated data */
1269 }
1270 else if(rep_data_length == 1)
1271 {
1272 LOG_FORMAT(p_ctx, "Compressed Payload Data");
1273 p_state->media_object_pts_delta = READ_U8(p_ctx, "Presentation Time Delta") * UINT64_C(1000);
1274 p_state->compressed_payloads = 1;
1275
1276 /* Move the pts from media_object_off where it was read, and adjust it */
1277 p_state->media_object_off *= UINT64_C(1000);
1278 p_state->media_object_pts = p_state->media_object_off - p_state->media_object_pts_delta;
1279 p_state->media_object_off = 0;
1280 p_state->media_object_size = 0;
1281 }
1282 else
1283 {
1284 p_state->media_object_size = 0;
1285 p_state->media_object_pts = p_state->send_time;
1286 p_state->compressed_payloads = 0;
1287 }
1288
1289 if(p_state->media_object_pts > module->preroll + module->time_offset)
1290 p_state->media_object_pts -= (module->preroll + module->time_offset);
1291 else p_state->media_object_pts = 0;
1292
1293 p_state->payload_size = p_state->size - p_state->padding_size - (STREAM_POSITION(p_ctx) - p_state->start);
1294 if(p_state->multiple_payloads)
1295 {
1296 p_state->payload_size = READ_VLC(p_ctx, p_state->payload_lt, 0, "Payload Length");
1297 if(!p_state->payload_size) return VC_CONTAINER_ERROR_CORRUPTED;
1298 }
1299 else
1300 LOG_FORMAT(p_ctx, "Payload Length: %i", p_state->payload_size);
1301
1302 if(p_state->payload_size >= p_state->size) return VC_CONTAINER_ERROR_CORRUPTED;
1303
1304 p_state->subpayload_size = p_state->payload_size;
1305
1306 /* Update current_offset to reflect the variable number of bytes we just read */
1307 p_state->current_offset = STREAM_POSITION(p_ctx) - p_state->start;
1308
1309 /* Sanity check offset */
1310 if(p_state->current_offset > p_state->size) return VC_CONTAINER_ERROR_CORRUPTED;
1311
1312 return STREAM_STATUS(p_ctx);
1313}
1314
1315/*****************************************************************************/
1316static VC_CONTAINER_STATUS_T asf_read_object_data( VC_CONTAINER_T *p_ctx, int64_t size )
1317{
1318 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1319 unsigned int i;
1320 VC_CONTAINER_PARAM_UNUSED(size);
1321
1322 SKIP_GUID(p_ctx, "File ID");
1323 SKIP_U64(p_ctx, "Total Data Packets");
1324 SKIP_U16(p_ctx, "Reserved");
1325 module->data_offset = STREAM_POSITION(p_ctx);
1326
1327 /* Initialise state for all tracks */
1328 module->packet_state.start = module->data_offset;
1329 for(i = 0; i < p_ctx->tracks_num; i++)
1330 {
1331 VC_CONTAINER_TRACK_T *p_track = p_ctx->tracks[i];
1332 p_track->priv->module->p_packet_state = &module->packet_state;
1333 }
1334
1335 return STREAM_STATUS(p_ctx);
1336}
1337
1338/*****************************************************************************/
1339/* Read the next sub-payload or next payload */
1340static VC_CONTAINER_STATUS_T asf_read_next_payload_header( VC_CONTAINER_T *p_ctx,
1341 ASF_PACKET_STATE *p_state, uint32_t *pi_track, uint32_t *pi_length)
1342{
1343 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1344 VC_CONTAINER_STATUS_T status;
1345
1346 if(p_state->subpayload_size)
1347 {
1348 /* We still haven't read the current subpayload, return the info we already have */
1349 goto end;
1350 }
1351
1352 /* Check if we're done reading a packet */
1353 if(p_state->current_payload >= p_state->num_payloads)
1354 {
1355 /* Skip the padding at the end */
1356 if(p_state->size)
1357 {
1358 int32_t pad_length = p_state->size - (STREAM_POSITION(p_ctx) - p_state->start);
1359 if(pad_length < 0) return VC_CONTAINER_ERROR_CORRUPTED;
1360 SKIP_BYTES(p_ctx, pad_length); /* Padding */
1361 }
1362
1363 /* Read the header for the next packet */
1364 module->object_level = 0; /* For debugging */
1365 status = asf_read_packet_header( p_ctx, p_state, (uint64_t)0/*size???*/ );
1366 module->object_level = 1; /* For debugging */
1367 if(status != VC_CONTAINER_SUCCESS) return status;
1368 }
1369
1370 /* Check if we're done reading a payload */
1371 if(!p_state->payload_size)
1372 {
1373 /* Read the payload header */
1374 status = asf_read_payload_header( p_ctx, p_state );
1375 if(status != VC_CONTAINER_SUCCESS) return status;
1376 }
1377
1378 /* For compressed payloads, payload_size != subpayload_size */
1379 if(p_state->compressed_payloads && p_state->payload_size)
1380 {
1381 p_state->payload_size--;
1382 p_state->subpayload_size = READ_U8(p_ctx, "Sub-Payload Data Length");
1383 if(p_state->subpayload_size > p_state->payload_size)
1384 {
1385 /* TODO: do something ? */
1386 LOG_DEBUG(p_ctx, "subpayload is too big");
1387 p_state->subpayload_size = p_state->payload_size;
1388 }
1389 p_state->media_object_off = 0;
1390 p_state->media_object_size = p_state->subpayload_size;
1391 p_state->media_object_pts += p_state->media_object_pts_delta;
1392 }
1393
1394 end:
1395 /* We've read the payload header, return the requested info */
1396 if(pi_track) *pi_track = module->stream_number_to_index[p_state->stream_num & 0x7F];
1397 if(pi_length) *pi_length = p_state->subpayload_size;
1398
1399 p_state->current_offset = STREAM_POSITION(p_ctx) - p_state->start;
1400 return VC_CONTAINER_SUCCESS;
1401}
1402
1403/*****************************************************************************/
1404/* read the next payload (not sub-payload) */
1405static VC_CONTAINER_STATUS_T asf_read_next_payload( VC_CONTAINER_T *p_ctx,
1406 ASF_PACKET_STATE *p_state, uint8_t *p_data, uint32_t *pi_size )
1407{
1408 uint32_t subpayload_size = p_state->subpayload_size;
1409
1410 if(p_data && *pi_size < subpayload_size) subpayload_size = *pi_size;
1411
1412 if(!p_state->subpayload_size)
1413 return VC_CONTAINER_SUCCESS;
1414
1415 p_state->payload_size -= subpayload_size;
1416 if(!p_state->payload_size) p_state->current_payload++;
1417 p_state->subpayload_size -= subpayload_size;
1418 p_state->media_object_off += subpayload_size;
1419
1420 if(p_data) *pi_size = READ_BYTES(p_ctx, p_data, subpayload_size);
1421 else *pi_size = SKIP_BYTES(p_ctx, subpayload_size);
1422
1423 p_state->current_offset += subpayload_size;
1424
1425 if(*pi_size!= subpayload_size)
1426 return STREAM_STATUS(p_ctx);
1427
1428 return VC_CONTAINER_SUCCESS;
1429}
1430
1431/******************************************************************************
1432Functions exported as part of the Container Module API
1433 *****************************************************************************/
1434/*****************************************************************************/
1435/** Read data from the ASF file
1436
1437@param p_ctx Context for the file being read from
1438
1439@param p_packet Packet information. Includes data buffer and stream ID as aprropriate.
1440
1441@param flags Flags controlling the read.
1442 May request reading only, skipping a packet or force access to a set track.
1443
1444******************************************************************************/
1445static VC_CONTAINER_STATUS_T asf_reader_read( VC_CONTAINER_T *p_ctx,
1446 VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
1447{
1448 VC_CONTAINER_MODULE_T *global_module = p_ctx->priv->module;
1449 VC_CONTAINER_TRACK_MODULE_T *track_module;
1450 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
1451 ASF_PACKET_STATE *p_state;
1452 uint32_t buffer_size = 0, track, data_size;
1453 uint64_t state_pos;
1454
1455 LOG_DEBUG(p_ctx, "asf_reader_read track %"PRIu32" flags %u", p_packet->track, flags);
1456
1457 /* If a specific track has been selected, we need to use the track packet state */
1458 if(flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
1459 {
1460 vc_container_assert(p_packet->track < p_ctx->tracks_num);
1461 /* The state to use is the one referred to by the track we selected */
1462 p_state = p_ctx->tracks[p_packet->track]->priv->module->p_packet_state;
1463 }
1464 else
1465 {
1466 /* No specific track was selected. Read the next data from the global position. */
1467 p_state = &global_module->packet_state;
1468 }
1469
1470 /* Stop if the stream can't be read */
1471 if(p_state->eos) return VC_CONTAINER_ERROR_EOS;
1472 if(p_state->corrupted) return VC_CONTAINER_ERROR_CORRUPTED;
1473
1474 /* If we aren't in the right position in the file go there now. */
1475 state_pos = p_state->start + p_state->current_offset;
1476 if ((uint64_t)STREAM_POSITION(p_ctx) != state_pos)
1477 {
1478 LOG_DEBUG(p_ctx, "seeking from %"PRIu64" to %"PRIu64, STREAM_POSITION(p_ctx), state_pos);
1479 SEEK(p_ctx, state_pos);
1480 }
1481
1482 /* Look at the next payload header */
1483 status = asf_read_next_payload_header( p_ctx, p_state, &track, &data_size );
1484 if((status == VC_CONTAINER_ERROR_CORRUPTED)
1485 && (p_state->bad_packets < ASF_MAX_CONSECUTIVE_CORRUPTED_PACKETS))
1486 {
1487 /* If the current packet is corrupted we will try to search for the next packet */
1488 uint32_t corrupted = p_state->bad_packets;
1489 LOG_DEBUG(p_ctx, "packet offset %"PRIi64" is corrupted", p_state->start);
1490 memset(p_state, 0, sizeof(*p_state));
1491 p_state->bad_packets = corrupted + 1;
1492
1493 /* TODO: flag discontinuity */
1494
1495 if(asf_find_packet_header(p_ctx, p_state) == VC_CONTAINER_SUCCESS)
1496 {
1497 p_state->start = STREAM_POSITION(p_ctx);
1498 return VC_CONTAINER_ERROR_CONTINUE;
1499 }
1500 }
1501 if(status == VC_CONTAINER_ERROR_EOS) p_state->eos = true;
1502 if(status == VC_CONTAINER_ERROR_CORRUPTED) p_state->corrupted = true;
1503 if(status != VC_CONTAINER_SUCCESS)
1504 {
1505 return status;
1506 }
1507
1508 p_state->bad_packets = 0;
1509
1510 /* bad track number or track is disabled */
1511 if(track >= p_ctx->tracks_num || !p_ctx->tracks[track]->is_enabled)
1512 {
1513 LOG_DEBUG(p_ctx, "skipping packet because track %u is invalid or disabled", track);
1514
1515 /* Skip payload by reading with a null buffer */
1516 status = asf_read_next_payload(p_ctx, p_state, 0, &data_size );
1517 if(status != VC_CONTAINER_SUCCESS) return status;
1518 return VC_CONTAINER_ERROR_CONTINUE;
1519 }
1520
1521 track_module = p_ctx->tracks[track]->priv->module;
1522
1523 /* If we are reading from the global state, and the track we found is not on the global state,
1524 * either skip the data or reconnect it to the global state */
1525 if ((p_state == &global_module->packet_state) &&
1526 (track_module->p_packet_state != &global_module->packet_state))
1527 {
1528 uint64_t track_pos =
1529 track_module->p_packet_state->start
1530 + track_module->p_packet_state->current_offset;
1531
1532 /* Check if the end of the current packet is beyond the track's position */
1533 if (track_pos > state_pos + track_module->p_packet_state->size)
1534 {
1535 LOG_DEBUG(p_ctx, "skipping packet from track %u as it has already been read", track);
1536 status = asf_read_next_payload(p_ctx, p_state, 0, &data_size);
1537
1538 if(status != VC_CONTAINER_SUCCESS) return status;
1539 return VC_CONTAINER_ERROR_CONTINUE;
1540 }
1541 else
1542 {
1543 LOG_DEBUG(p_ctx, "switching track index %u location %"PRIu64" back to global state", track, track_pos);
1544 track_module->p_packet_state = &global_module->packet_state;
1545
1546 /* Update the global state to the precise position */
1547 global_module->packet_state = track_module->local_packet_state;
1548 return VC_CONTAINER_ERROR_CONTINUE;
1549 }
1550 }
1551
1552 /* If we are forcing, and the data is from a different track, skip it.
1553 * We may need to move the track we want onto a local state. */
1554 if ((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
1555 && (track != p_packet->track))
1556 {
1557 track_module = p_ctx->tracks[p_packet->track]->priv->module;
1558
1559 /* If the track we found is on the same state as the track we want they must both be on the global state */
1560 if (p_ctx->tracks[track]->priv->module->p_packet_state == p_state)
1561 {
1562 LOG_DEBUG(p_ctx, "switching track index %u location %"PRIu64" away from global state", p_packet->track, state_pos);
1563
1564 /* Change the track we want onto a local state */
1565 track_module->p_packet_state = &track_module->local_packet_state;
1566
1567 /* Copy the global state into the local state for the track we are forcing */
1568 track_module->local_packet_state = global_module->packet_state;
1569 }
1570
1571 LOG_DEBUG(p_ctx, "skipping packet from track %u while forcing %u", track, p_packet->track);
1572 status = asf_read_next_payload(p_ctx, track_module->p_packet_state, 0, &data_size );
1573 return VC_CONTAINER_ERROR_CONTINUE;
1574 }
1575
1576 /* If we arrive here either the data is from the track we are forcing, or we are not forcing
1577 * and we haven't already read the data while forcing that track */
1578
1579 /* If skip, and no info required, skip over it and return now. */
1580 if((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO))
1581 return asf_read_next_payload(p_ctx, p_state, 0, &data_size );
1582
1583 /* Fill-in the packet information */
1584 if(p_state->media_object_pts == ASF_UNKNOWN_PTS || p_state->media_object_off)
1585 p_packet->dts = p_packet->pts = VC_CONTAINER_TIME_UNKNOWN;
1586 else
1587 p_packet->dts = p_packet->pts = p_state->media_object_pts;
1588
1589 p_packet->flags = 0;
1590
1591 if(p_state->stream_num >> 7) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
1592
1593 if(!p_state->media_object_off) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
1594
1595 if(p_state->media_object_size &&
1596 p_state->media_object_off + data_size >= p_state->media_object_size)
1597 p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
1598
1599 if(!p_state->media_object_size)
1600 p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
1601
1602 p_packet->track = track;
1603
1604 p_packet->frame_size = p_state->media_object_size;
1605
1606 p_packet->size = data_size;
1607
1608 /* If the skip flag is set (Info must have been too) skip the data and return */
1609 if(flags & VC_CONTAINER_READ_FLAG_SKIP)
1610 {
1611 /* Skip payload by reading with a null buffer */
1612 return asf_read_next_payload(p_ctx, p_state, 0, &data_size );
1613 }
1614 else if(flags & VC_CONTAINER_READ_FLAG_INFO)
1615 {
1616 return VC_CONTAINER_SUCCESS;
1617 }
1618
1619 /* Read the payload data */
1620 buffer_size = p_packet->buffer_size;
1621 status = asf_read_next_payload(p_ctx, p_state, p_packet->data, &buffer_size );
1622 if(status != VC_CONTAINER_SUCCESS)
1623 {
1624 /* FIXME */
1625 return status;
1626 }
1627
1628 p_packet->size = buffer_size;
1629 if(buffer_size != data_size)
1630 p_packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
1631 LOG_DEBUG(p_ctx, "asf_reader_read exit %u PTS %"PRIi64" track %"PRIu32, status, p_packet->pts, track);
1632
1633 return status;
1634}
1635
1636/*****************************************************************************/
1637static VC_CONTAINER_STATUS_T asf_reader_index_find_time( VC_CONTAINER_T *p_ctx,
1638 VC_CONTAINER_TRACK_MODULE_T* track_module, int64_t time, uint32_t *packet_num, bool forward )
1639{
1640 VC_CONTAINER_STATUS_T status;
1641 uint32_t entry, previous_packet_num;
1642 bool eos = false;
1643
1644 /* Default to beginning of file in case of error */
1645 *packet_num = 0;
1646
1647 /* Special case - time zero is beginning of file */
1648 if(time == 0) {return VC_CONTAINER_SUCCESS;}
1649
1650 /* Sanity checking */
1651 if(!track_module->simple_index.num_entries) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
1652 if(!track_module->simple_index.time_interval) return VC_CONTAINER_ERROR_CORRUPTED;
1653
1654 entry = time / track_module->simple_index.time_interval;
1655 LOG_DEBUG(p_ctx, "entry: %i, offset: %"PRIi64", interv: %"PRIi64, entry,
1656 track_module->simple_index.offset, track_module->simple_index.time_interval);
1657 if(entry >= track_module->simple_index.num_entries)
1658 {
1659 entry = track_module->simple_index.num_entries - 1;
1660 eos = true;
1661 }
1662
1663 /* Fetch the entry from the index */
1664 status = SEEK(p_ctx, track_module->simple_index.offset + 6 * entry);
1665 if(status != VC_CONTAINER_SUCCESS) return status;
1666 *packet_num = READ_U32(p_ctx, "Packet Number");
1667 if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) return STREAM_STATUS(p_ctx);
1668
1669 /* When asking for the following keyframe we need to find the next entry with a greater
1670 * packet number */
1671 previous_packet_num = *packet_num;
1672 while(!eos && forward && previous_packet_num == *packet_num)
1673 {
1674 if(++entry == track_module->simple_index.num_entries) {eos = true; break;}
1675 status = SEEK(p_ctx, track_module->simple_index.offset + 6 * entry);
1676 if(status != VC_CONTAINER_SUCCESS) break;
1677 *packet_num = READ_U32(p_ctx, "Packet Number");
1678 if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) break;
1679 }
1680
1681 if(eos && track_module->simple_index.incomplete) return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
1682 else if(eos) return VC_CONTAINER_ERROR_EOS;
1683 else return STREAM_STATUS(p_ctx);
1684}
1685
1686#if 0
1687/*****************************************************************************/
1688static VC_CONTAINER_STATUS_T asf_reader_index_find_packet( VC_CONTAINER_T *p_ctx,
1689 unsigned int track, uint32_t *packet_num, bool forward )
1690{
1691 VC_CONTAINER_STATUS_T status;
1692 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1693 VC_CONTAINER_TRACK_MODULE_T *track_module = 0;
1694 uint32_t i, prev_packet_num = 0, next_packet_num;
1695 bool eos = false;
1696
1697 /* Sanity checking */
1698 if(track >= p_ctx->tracks_num) return VC_CONTAINER_ERROR_FAILED;
1699 track_module = p_ctx->tracks[track]->priv->module;
1700 if(!track_module->num_index_entries) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
1701 if(!track_module->index_time_interval) return VC_CONTAINER_ERROR_CORRUPTED;
1702
1703 status = SEEK(p_ctx, track_module->index_offset);
1704 if(status != VC_CONTAINER_SUCCESS) return status;
1705
1706 /* Loop through all the entries in the index */
1707 for(i = 0; i < track_module->num_index_entries; i++)
1708 {
1709 next_packet_num = READ_U32(p_ctx, "Packet Number");
1710 SKIP_U16(p_ctx, "Packet Count");
1711 if(next_packet_num > *packet_num) break;
1712 if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) break;
1713 prev_packet_num = next_packet_num;
1714 }
1715 if(i == track_module->num_index_entries ) eos = true;
1716
1717 if(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS && !eos)
1718 {
1719 if(forward) *packet_num = next_packet_num;
1720 else *packet_num = prev_packet_num;
1721 }
1722
1723 if(eos && track_module->index_incomplete) return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
1724 else if(eos) return VC_CONTAINER_ERROR_EOS;
1725 else return STREAM_STATUS(p_ctx);
1726}
1727#endif
1728
1729/*****************************************************************************/
1730static VC_CONTAINER_STATUS_T asf_reader_find_next_frame( VC_CONTAINER_T *p_ctx,
1731 unsigned int track, ASF_PACKET_STATE *p_state, bool keyframe, bool timeout )
1732{
1733 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
1734 uint32_t data_track, data_size;
1735 unsigned int packets = 0;
1736
1737 if(p_ctx->tracks[track]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO)
1738 keyframe = false;
1739
1740 /* We still need to go to the right payload */
1741 while(status == VC_CONTAINER_SUCCESS &&
1742 (!timeout || packets++ < ASF_MAX_SEARCH_PACKETS))
1743 {
1744 status = asf_read_next_payload_header( p_ctx, p_state, &data_track, &data_size );
1745 if(status != VC_CONTAINER_SUCCESS) break;
1746
1747 if(data_track == track && ((p_state->stream_num >> 7) || !keyframe) &&
1748 !p_state->media_object_off) break;
1749
1750 /* Skip payload */
1751 status = asf_read_next_payload(p_ctx, p_state, 0, &data_size );
1752 }
1753
1754 return status;
1755}
1756
1757/*****************************************************************************/
1758/* Helper for asf_reader_seek - seek when there is a top-level index (spec section 6.2) */
1759static VC_CONTAINER_STATUS_T seek_by_top_level_index(
1760 VC_CONTAINER_T *p_ctx,
1761 int64_t *p_time,
1762 VC_CONTAINER_SEEK_MODE_T mode,
1763 VC_CONTAINER_SEEK_FLAGS_T flags)
1764{
1765 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
1766 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1767 unsigned index;
1768 uint64_t time = 0;
1769 uint64_t block_address = module->top_level_index.blocks_offset;
1770 uint64_t track_positions[ASF_TRACKS_MAX];
1771
1772 VC_CONTAINER_PARAM_UNUSED(mode);
1773 LOG_DEBUG(p_ctx, "seek_by_top_level_index");
1774
1775 for (index = 0; index < ASF_TRACKS_MAX; ++index)
1776 {
1777 /* Set all to a stupid value */
1778 track_positions[index] = UINT64_MAX;
1779 }
1780
1781 /* Loop through the index blocks to find the one(s) that deal with the time(s) in question.
1782 * Note that most ASF files only have one index block. */
1783 for (index = 0; index < module->top_level_index.block_count; ++index)
1784 {
1785 uint64_t block_duration, block_position;
1786 uint32_t index_entry_count, stream;
1787 LOG_DEBUG(p_ctx, "looking for index blocks at offset %"PRIu64, block_address);
1788 status = SEEK(p_ctx, block_address);
1789 if(status != VC_CONTAINER_SUCCESS) return status;
1790
1791 /* Read the number of entries for this index block. */
1792 index_entry_count = READ_U32(p_ctx, "Index Entry Count");
1793
1794 /* Turn into a duration */
1795 block_duration = (uint64_t)index_entry_count * module->top_level_index.entry_time_interval;
1796
1797 /* Go through each stream */
1798 for (stream = 0; stream < p_ctx->tracks_num; ++stream)
1799 {
1800 /* Work out the track's target time */
1801 uint64_t track_time = *p_time + module->preroll + module->time_offset;
1802
1803 /* Have we the correct index block for the seek time? */
1804 if ((time <= track_time) && (track_time < time + block_duration))
1805 {
1806 /* We have the correct index block for the seek time. Work out where in it. */
1807 uint32_t block_index = (track_time - time) / module->top_level_index.entry_time_interval;
1808 uint64_t active_specifier = module->top_level_index.active_specifiers[stream];
1809 uint64_t new_position;
1810
1811 /* Read the Block Positions value for the correct specifier */
1812 status = SEEK(p_ctx,
1813 block_address + INT64_C(4)
1814 + active_specifier * INT64_C(8));
1815 if (status != VC_CONTAINER_SUCCESS)
1816 {
1817 return status;
1818 }
1819 block_position = READ_U32(p_ctx, "Block Position");
1820
1821 /* Read the target address for the stream */
1822 status = SEEK(p_ctx, block_address + 4 /* skip index entry count */
1823 + (UINT64_C(8) * module->top_level_index.specifiers_count) /* block positions */
1824 + (UINT64_C(4) * module->top_level_index.specifiers_count * block_index) /* prior index entries */
1825 + (UINT64_C(4) * active_specifier)); /* correct specifier */
1826 LOG_DEBUG(p_ctx, "reading at %"PRIu64, STREAM_POSITION(p_ctx));
1827
1828 new_position = module->data_offset + block_position + (uint64_t)READ_U32(p_ctx, "Offset");
1829 LOG_DEBUG(p_ctx, "actual address for stream %"PRIu32" = %"PRIu64, stream, new_position);
1830 track_positions[stream] = new_position;
1831 }
1832 }
1833
1834 /* Work out where the next block is */
1835 block_address += (UINT64_C(8) * module->top_level_index.specifiers_count)
1836 + (UINT64_C(4) * module->top_level_index.specifiers_count * index_entry_count);
1837 }
1838
1839 return seek_to_positions(p_ctx, track_positions, p_time, flags, 0, 0);
1840}
1841
1842/* Helper for asf_reader_seek -
1843 * Given a set of positions seek the tracks. The status is the result of physically seeking each one.
1844 * It is expected that the positions will be before *p_time; if the flags require it search
1845 * for the next keyframe that is at or above *p_time. */
1846static VC_CONTAINER_STATUS_T seek_to_positions(VC_CONTAINER_T *p_ctx, uint64_t track_positions[ASF_TRACKS_MAX],
1847 int64_t *p_time, VC_CONTAINER_SEEK_FLAGS_T flags,
1848 unsigned int start_track, bool seek_on_start_track)
1849{
1850 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1851 uint64_t global_position = UINT64_MAX;
1852 unsigned int lowest_track, index, tracks;
1853 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
1854
1855 int64_t track_best_pts[ASF_TRACKS_MAX];
1856
1857 if (*p_time == 0)
1858 {
1859 // Special case: Time 0 means beginning of file. Don't search for the matching packet(s).
1860 memset(&module->packet_state, 0, sizeof(module->packet_state));
1861 module->packet_state.start = track_positions[0];
1862 status = SEEK(p_ctx, module->packet_state.start);
1863
1864 // Set each track to using the global state
1865 for(index = 0; index < p_ctx->tracks_num; index++)
1866 {
1867 p_ctx->tracks[index]->priv->module->p_packet_state = &module->packet_state;
1868 }
1869
1870 return status;
1871 }
1872
1873 for(tracks = 0, index = start_track; tracks < p_ctx->tracks_num;
1874 tracks++, index = (index+1) % p_ctx->tracks_num)
1875 {
1876 uint32_t data_size;
1877
1878 /* Use an on-stack packet state. We can't use the global state, as we must leave it at
1879 * the lowest position. We can't use any track's private state, as we will move it past
1880 * the desired location. */
1881 ASF_PACKET_STATE private_state;
1882 memset(&private_state, 0, sizeof(private_state));
1883
1884 track_best_pts[index] = INT64_MAX;
1885
1886 status = SEEK(p_ctx, track_positions[index]);
1887
1888 /* loop until we find the packet we're looking for.
1889 * stop when we've seen a big enough PTS, and are on a key frame */
1890 while(status == VC_CONTAINER_SUCCESS)
1891 {
1892 /* Get the next key-frame */
1893 status = asf_reader_find_next_frame(p_ctx, index, &private_state, true, true);
1894 if(status == VC_CONTAINER_SUCCESS)
1895 {
1896 /* Get the PTS, if any */
1897 int64_t pts = (int64_t)private_state.media_object_pts;
1898
1899 if(pts != ASF_UNKNOWN_PTS)
1900 {
1901 if ((track_best_pts[index] == INT64_MAX) /* we don't have a time yet */
1902 || (pts <= *p_time) /* it's before our target */
1903 || (flags & VC_CONTAINER_SEEK_FLAG_FORWARD)) /* we want after target */
1904 {
1905 /* Store this time. It's the best yet. */
1906 track_best_pts[index] = pts;
1907
1908 /* Update the desired position */
1909 track_positions[index] = private_state.start + private_state.current_offset;
1910
1911 /* Copy the local state into this track's private state */
1912 p_ctx->tracks[index]->priv->module->local_packet_state = private_state;
1913
1914 LOG_DEBUG(p_ctx, "seek forward track %u to pts %"PRIu64,
1915 index, track_best_pts[index]);
1916 }
1917
1918 /* If we've got to our target time we can stop. */
1919 if (pts >= *p_time)
1920 {
1921 /* Then stop. */
1922 break;
1923 }
1924 }
1925
1926 status = asf_read_next_payload(p_ctx, &private_state, 0, &data_size );
1927 }
1928 }
1929
1930 /* If we are seeking using a specific track, usually this is the video track
1931 * and we want all the other tracks to start at the same time or later */
1932 if (seek_on_start_track && start_track == index)
1933 {
1934 flags |= VC_CONTAINER_SEEK_FLAG_FORWARD;
1935 *p_time = track_best_pts[index];
1936 }
1937
1938 {
1939 ASF_PACKET_STATE *p_state = &p_ctx->tracks[index]->priv->module->local_packet_state;
1940
1941 LOG_DEBUG(p_ctx, "seek track %u to pts %"PRIu64" (key:%i,moo:%i)",
1942 index, track_best_pts[index], p_state->stream_num >> 7, p_state->media_object_off);
1943 }
1944 }
1945
1946 /* Find the smallest track address in track_positions. This will be the global position */
1947 /* Also the lowest PTS in track_best_pts, this will be the new global PTS */
1948 for (index = 0, lowest_track = 0; index < p_ctx->tracks_num; ++index)
1949 {
1950 /* If it is smaller, remember it */
1951 if (track_positions[index] < global_position)
1952 {
1953 global_position = track_positions[index];
1954 lowest_track = index;
1955 }
1956
1957 /* Put the lowest PTS into entry 0 of the array */
1958 if ((track_best_pts[index] != INT64_MAX) && (track_best_pts[index] < track_best_pts[0]))
1959 {
1960 track_best_pts[0] = track_best_pts[index];
1961 }
1962 }
1963
1964 /* Update the caller with the lowest real PTS, if any. (we may have already done this above) */
1965 if (track_best_pts[0] != INT64_MAX)
1966 {
1967 *p_time = track_best_pts[0];
1968 }
1969 else
1970 {
1971 LOG_DEBUG(p_ctx, "no PTS suitable to update the caller");
1972 }
1973
1974 /* As we did an extra read on the index track past the desired location seek back to it */
1975 status = SEEK(p_ctx, global_position);
1976
1977 /* Copy the packet state for the stream with the lowest address into the global state */
1978 module->packet_state = p_ctx->tracks[lowest_track]->priv->module->local_packet_state;
1979
1980 for(index = 0; index < p_ctx->tracks_num; index++)
1981 {
1982 VC_CONTAINER_TRACK_MODULE_T* track_mod = p_ctx->tracks[index]->priv->module;
1983
1984 /* If the track position is the global position, or it is invalid, use the global state */
1985 if ((track_positions[index] <= global_position) || (track_positions[index] == UINT64_MAX))
1986 {
1987 track_mod->p_packet_state = &module->packet_state;
1988 }
1989 else
1990 {
1991 /* Track is not at the global position. Use the local state. */
1992 LOG_DEBUG(p_ctx, "track %u local position %"PRIu64, index, track_positions[index]);
1993 track_mod->p_packet_state = &track_mod->local_packet_state;
1994 }
1995 }
1996
1997 return status;
1998}
1999
2000/*****************************************************************************/
2001/* Seek to a location in the file, using whatever indices are available
2002 * If flags bit VC_CONTAINER_SEEK_FLAG_FORWARD is set the position is guaranteed to
2003 * be a keyframe at or after the requested location. Conversely if it is not set
2004 * the position is guaranteed to be at or before the request. */
2005static VC_CONTAINER_STATUS_T asf_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *p_time,
2006 VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
2007{
2008 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_EOS; /* initialised to known fail state */
2009 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
2010 unsigned int stream;
2011
2012 VC_CONTAINER_PARAM_UNUSED(mode);
2013
2014 LOG_DEBUG(p_ctx, "asf_reader_seek");
2015
2016 /* Prefer the top-level index to the simple index - it has byte offsets not packet offsets,
2017 * and is likely to have separate tables for every track */
2018 if (module->top_level_index.block_count)
2019 {
2020 status = seek_by_top_level_index(p_ctx, p_time, mode, flags);
2021 }
2022 else
2023 {
2024 uint64_t track_positions[ASF_TRACKS_MAX];
2025 int seek_track = -1;
2026 uint32_t packet_num;
2027 uint64_t new_position;
2028
2029 if (*p_time == 0)
2030 {
2031 // Special optimisation - for time zero just go to the beginning.
2032 packet_num = 0;
2033 }
2034 /* If there is a simple index use the packet number from it */
2035 else if (module->simple_index_track)
2036 {
2037 /* Correct time desired */
2038 uint64_t track_time = *p_time + module->preroll + module->time_offset;
2039
2040 LOG_DEBUG(p_ctx, "using simple index");
2041
2042 /* Search the index for the correct packet */
2043 status = asf_reader_index_find_time(p_ctx, module->simple_index_track, track_time,
2044 &packet_num, flags & VC_CONTAINER_SEEK_FLAG_FORWARD);
2045 }
2046 else
2047 {
2048 /* No index at all. Use arithmetic to guess the packet number. */
2049 LOG_DEBUG(p_ctx, "index not usable %u", (unsigned)status);
2050
2051 if (module->packets_num == 0)
2052 {
2053 /* This is a broadcast stream, and we can't do the arithmetic.
2054 * Set it to a value that will guarantee a seek fail. */
2055 LOG_DEBUG(p_ctx, "no packets in file");
2056 packet_num = UINT32_MAX;
2057 }
2058 else
2059 {
2060 packet_num = *p_time * module->packets_num / module->duration;
2061 }
2062 }
2063
2064 /* calculate the byte address of the packet, relative to the start of data */
2065 new_position = (uint64_t)packet_num * (uint64_t)module->packet_size;
2066
2067 LOG_DEBUG(p_ctx, "packet number %"PRIu32" approx byte offset %"PRIu64 , packet_num, new_position + module->data_offset);
2068 if (new_position > (uint64_t)module->data_size)
2069 {
2070 new_position = module->data_size;
2071 LOG_DEBUG(p_ctx, "arithmetic error, seeking to end of file %" PRIu64 , new_position + module->data_offset);
2072 }
2073
2074 new_position += module->data_offset;
2075
2076 for(stream = 0; stream < p_ctx->tracks_num; stream++)
2077 {
2078 /* Use the 1st enabled video track as the seek stream */
2079 if(p_ctx->tracks[stream]->format->es_type ==
2080 VC_CONTAINER_ES_TYPE_VIDEO &&
2081 p_ctx->tracks[stream]->is_enabled && seek_track < 0)
2082 seek_track = stream;
2083
2084 track_positions[stream] = new_position;
2085 } /* repeat for all tracks */
2086
2087 /* Work out if we actually got anywhere. If so, save the positions for the subsequent reads */
2088 status = seek_to_positions(p_ctx, track_positions, p_time, flags,
2089 seek_track < 0 ? 0 : seek_track, seek_track >= 0);
2090 }
2091
2092 return status;
2093}
2094
2095/*****************************************************************************/
2096static VC_CONTAINER_STATUS_T asf_reader_close( VC_CONTAINER_T *p_ctx )
2097{
2098 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
2099 unsigned int i;
2100
2101/* FIXME: metadata is currently shared across all readers so freeing
2102 it is left to the common layer but this isn't necessarily
2103 the best solution.
2104 for(i = 0; i <p_ctx->meta_num; i++)
2105 free(p_ctx->meta[i]);
2106 if(p_ctx->meta_num) free(p_ctx->meta);
2107 p_ctx->meta_num = 0;
2108*/
2109 for(i = 0; i < p_ctx->tracks_num; i++)
2110 vc_container_free_track(p_ctx, p_ctx->tracks[i]);
2111 p_ctx->tracks_num = 0;
2112 free(module);
2113 return VC_CONTAINER_SUCCESS;
2114}
2115
2116/*****************************************************************************/
2117VC_CONTAINER_STATUS_T asf_reader_open( VC_CONTAINER_T *p_ctx )
2118{
2119 VC_CONTAINER_MODULE_T *module = 0;
2120 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
2121 unsigned int i;
2122 GUID_T guid;
2123
2124 /* Check for an ASF top-level header object */
2125 if(PEEK_BYTES(p_ctx, (uint8_t *)&guid, sizeof(guid)) < sizeof(guid) ||
2126 memcmp(&guid, &asf_guid_header, sizeof(guid)))
2127 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
2128
2129 /*
2130 * We are dealing with an ASF file
2131 */
2132
2133 /* Allocate our context */
2134 module = malloc(sizeof(*module));
2135 if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
2136 memset(module, 0, sizeof(*module));
2137
2138 /* Set the translation table to all error values */
2139 memset(&module->stream_number_to_index, 0xff, sizeof(module->stream_number_to_index));
2140 p_ctx->priv->module = module;
2141 p_ctx->tracks = module->tracks;
2142
2143 /* Read the top level header object */
2144 status = asf_read_object(p_ctx, INT64_C(0));
2145 if(status != VC_CONTAINER_SUCCESS)
2146 goto error;
2147
2148 /* Bail out if we didn't find a track */
2149 if(!p_ctx->tracks_num) {status = VC_CONTAINER_ERROR_NO_TRACK_AVAILABLE; goto error;}
2150
2151 /*
2152 * The top level data object must come next
2153 */
2154 if(READ_GUID(p_ctx, &guid, "Object ID") != sizeof(guid) ||
2155 memcmp(&guid, &asf_guid_data, sizeof(guid)))
2156 goto error;
2157
2158 LOG_FORMAT(p_ctx, "Object Name: data");
2159 module->data_size = READ_U64(p_ctx, "Object Size");
2160
2161 /* If the data size was supplied remove the size of the common object header and the local header for this object */
2162 if(module->data_size) module->data_size -= ASF_OBJECT_HEADER_SIZE + 16 + 8 + 2;
2163
2164 /* Sanity check the data object size */
2165 if(module->data_size < 0)
2166 goto error;
2167
2168 module->object_level++;
2169 SKIP_GUID(p_ctx, "File ID");
2170 module->packets_num = READ_U64(p_ctx, "Total Data Packets");
2171 if(module->broadcast) module->packets_num = 0;
2172 SKIP_U16(p_ctx, "Reserved");
2173
2174 if (module->packet_size)
2175 {
2176 LOG_DEBUG(p_ctx, "object size %"PRIu64" means %f packets",
2177 module->data_size, (float)(module->data_size) / (float)(module->packet_size));
2178 }
2179
2180 module->data_offset = STREAM_POSITION(p_ctx);
2181 LOG_DEBUG(p_ctx, "expect end of data at address %"PRIu64, module->data_size + module->data_offset);
2182
2183 module->object_level--;
2184
2185 /*
2186 * We now have all the information we really need to start playing the stream
2187 */
2188
2189 /* Initialise state for all tracks */
2190 module->packet_state.start = module->data_offset;
2191 for(i = 0; i < p_ctx->tracks_num; i++)
2192 {
2193 VC_CONTAINER_TRACK_T *p_track = p_ctx->tracks[i];
2194 p_track->priv->module->p_packet_state = &module->packet_state;
2195 }
2196
2197 p_ctx->priv->pf_close = asf_reader_close;
2198 p_ctx->priv->pf_read = asf_reader_read;
2199 p_ctx->priv->pf_seek = asf_reader_seek;
2200
2201 if(STREAM_SEEKABLE(p_ctx))
2202 {
2203 p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
2204 p_ctx->capabilities |= VC_CONTAINER_CAPS_FORCE_TRACK;
2205 }
2206
2207 p_ctx->duration = module->duration;
2208
2209 /* Check if we're done */
2210 if(!module->data_size || !STREAM_SEEKABLE(p_ctx))
2211 return VC_CONTAINER_SUCCESS;
2212
2213 /* If the stream is seekable and not a broadcast stream, we want to use any index there
2214 * might be at the end of the stream */
2215
2216 /* Seek back to the end of the data object */
2217 if( SEEK(p_ctx, module->data_offset + module->data_size) == VC_CONTAINER_SUCCESS)
2218 {
2219 /* This will catch the simple index object if it is there */
2220 do {
2221 status = asf_read_object(p_ctx, INT64_C(0));
2222 } while(status == VC_CONTAINER_SUCCESS);
2223 }
2224
2225 for(i = 0; i < p_ctx->tracks_num; i++)
2226 {
2227 if(p_ctx->tracks[i]->priv->module->simple_index.offset)
2228 LOG_DEBUG(p_ctx, "track %i has an index", i);
2229 }
2230
2231 /* Seek back to the start of the data */
2232 return SEEK(p_ctx, module->data_offset);
2233
2234 error:
2235 if(status == VC_CONTAINER_SUCCESS) status = VC_CONTAINER_ERROR_FORMAT_INVALID;
2236 LOG_DEBUG(p_ctx, "asf: error opening stream (%i)", status);
2237 if(module) asf_reader_close(p_ctx);
2238 return status;
2239}
2240
2241/********************************************************************************
2242 Entrypoint function
2243 ********************************************************************************/
2244
2245#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
2246# pragma weak reader_open asf_reader_open
2247#endif
2248