blob: f0ac95afb7d69d01b048448401fb5ff8b9c1a25f
1 | /* ***** BEGIN LICENSE BLOCK ***** |
2 | * Source last modified: $Id: rm_parser_internal.c,v 1.2.2.1 2005/05/04 18:21:36 hubbe Exp $ |
3 | * |
4 | * REALNETWORKS CONFIDENTIAL--NOT FOR DISTRIBUTION IN SOURCE CODE FORM |
5 | * Portions Copyright (c) 1995-2005 RealNetworks, Inc. |
6 | * All Rights Reserved. |
7 | * |
8 | * The contents of this file, and the files included with this file, |
9 | * are subject to the current version of the Real Format Source Code |
10 | * Porting and Optimization License, available at |
11 | * https://helixcommunity.org/2005/license/realformatsource (unless |
12 | * RealNetworks otherwise expressly agrees in writing that you are |
13 | * subject to a different license). You may also obtain the license |
14 | * terms directly from RealNetworks. You may not use this file except |
15 | * in compliance with the Real Format Source Code Porting and |
16 | * Optimization License. There are no redistribution rights for the |
17 | * source code of this file. Please see the Real Format Source Code |
18 | * Porting and Optimization License for the rights, obligations and |
19 | * limitations governing use of the contents of the file. |
20 | * |
21 | * RealNetworks is the developer of the Original Code and owns the |
22 | * copyrights in the portions it created. |
23 | * |
24 | * This file, and the files included with this file, is distributed and |
25 | * made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, |
26 | * EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL |
27 | * SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF |
28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT |
29 | * OR NON-INFRINGEMENT. |
30 | * |
31 | * Technology Compatibility Kit Test Suite(s) Location: |
32 | * https://rarvcode-tck.helixcommunity.org |
33 | * |
34 | * Contributor(s): |
35 | * |
36 | * ***** END LICENSE BLOCK ***** */ |
37 | |
38 | #include <stdio.h> |
39 | #include <stdlib.h> |
40 | #include <string.h> |
41 | #include <memory.h> |
42 | //#include "includes.h" |
43 | //#include "ioapi.h" |
44 | //#include "datasrc.h" |
45 | #include "../include/helix_types.h" |
46 | #include "../include/helix_result.h" |
47 | #include "../include/helix_utils.h" |
48 | #include "rm_parser_internal.h" |
49 | #include "../include/rm_memory_default.h" |
50 | #include "../include/memory_utils.h" |
51 | #include "../include/pack_utils.h" |
52 | #include "../include/string_utils.h" |
53 | #include "../include/rm_stream.h" |
54 | #include "../include/packet_defines.h" |
55 | #include "../include/rv_format_info.h" |
56 | |
57 | #define RM_PARSER_LOGICAL_PREFIX "logical-" |
58 | #define RM_PARSER_LOGICAL_FILEINFO "logical-fileinfo" |
59 | #define RM_PARSER_NUM_RULE_BOOKS 9 |
60 | #define RM_PARSER_RULE_BOOK_BUFFER_SIZE 320 /* Big enough for format string and args */ |
61 | |
62 | #define RM_PARSER_LOGICAL_MULTIRATE_VIDEO "logical-video/x-pn-multirate-realvideo" |
63 | #define RM_PARSER_LOGICAL_MULTIRATE_AUDIO "logical-audio/x-pn-multirate-realaudio" |
64 | |
65 | static const char* g_pszRuleBook[] = { |
66 | /* VBR Real streams when max_bit_rate != 0 */ |
67 | "priority=%lu,AverageBandwidth=%lu,MaximumBandwidth=%lu," |
68 | "TimeStampDelivery=TRUE,PNMKeyFrameRule=T;" |
69 | "OnDepend=\"0\",priority=%lu,AverageBandwidth=0,MaximumBandwidth=0," |
70 | "TimeStampDelivery=TRUE,PNMNonKeyFrameRule=T;", |
71 | /* VBR Real streams when max_bit_rate == 0 */ |
72 | "priority=%lu,AverageBandwidth=%lu,TimeStampDelivery=TRUE,PNMKeyFrameRule=T;" |
73 | "OnDepend=\"0\",priority=%lu,AverageBandwidth=0,TimeStampDelivery=TRUE,PNMNonKeyFrameRule=T;", |
74 | /* Non-real-datatype VBR streams when max_bit_rate != 0 */ |
75 | "Marker=0,AverageBandwidth=%lu,MaximumBandwidth=%lu,TimeStampDelivery=TRUE;" |
76 | "Marker=1,AverageBandwidth=0,MaximumBandwidth=0,TimeStampDelivery=TRUE;", |
77 | /* Non-real-datatype VBR streams when max_bit_rate == 0 && avg_bit_rate != 0 */ |
78 | "Marker=0,AverageBandwidth=%lu,TimeStampDelivery=TRUE;" |
79 | "Marker=1,AverageBandwidth=0,TimeStampDelivery=TRUE;", |
80 | /* Non-real-datatype VBR streams when max_bit_rate == 0 && avg_bit_rate == 0 */ |
81 | "Marker=0,TimeStampDelivery=TRUE;" |
82 | "Marker=1,TimeStampDelivery=TRUE;", |
83 | /* CBR RealVideo */ |
84 | "#($Bandwidth >= %lu),priority=9,averagebandwidth=%lu,PNMKeyFrameRule=T;" |
85 | "#($Bandwidth >= %lu),OnDepend=\"0\",priority=5,averagebandwidth=0,PNMNonKeyFrameRule=T;" |
86 | "#($Bandwidth < %lu),priority=9,timestampdelivery=T,DropByN=T,PNMThinningRule=T;", |
87 | /* RealEvent streams */ |
88 | "TimeStampDelivery=T,priority=10,PNMKeyFrameRule=T;" |
89 | "TimeStampDelivery=T,priority=10,PNMNonKeyFrameRule=T;", |
90 | /* CBR RealAudio streams */ |
91 | "priority=5,averagebandwidth=%lu,PNMKeyFrameRule=T;" |
92 | "priority=5,averagebandwidth=0,PNMNonKeyFrameRule=T,OnDepend=\"0\",OffDepend=\"0\";", |
93 | /* CBR non-real-datatype streams */ |
94 | "Marker=0,priority=5,averagebandwidth=%lu;" |
95 | "Marker=1,priority=5,averagebandwidth=0;" |
96 | }; |
97 | |
98 | HX_RESULT rm_parseri_unpack_generic_hdr(rm_parser_internal* pInt, struct rm_generic_hdr* h) |
99 | { |
100 | HX_RESULT retVal = HXR_FAIL; |
101 | |
102 | if (pInt && h) { |
103 | /* Assign temporary variables */ |
104 | BYTE* pBuf = pInt->pReadBuffer; |
105 | UINT32 ulLen = pInt->ulNumBytesRead; |
106 | if (ulLen >= 10) { |
107 | /* Unpack the rm_generic_hdr */ |
108 | h->id = rm_unpack32(&pBuf, &ulLen); |
109 | h->size = rm_unpack32(&pBuf, &ulLen); |
110 | h->version = rm_unpack16(&pBuf, &ulLen); |
111 | /* Clear the return value */ |
112 | retVal = HXR_OK; |
113 | } |
114 | } |
115 | |
116 | return retVal; |
117 | } |
118 | |
119 | |
120 | HX_RESULT rm_parseri_unpack_file_hdr(rm_parser_internal* pInt) |
121 | { |
122 | HX_RESULT retVal = HXR_FAIL; |
123 | |
124 | if (pInt) { |
125 | /* Assign temporary variables */ |
126 | BYTE* pBuf = pInt->pReadBuffer; |
127 | UINT32 ulLen = pInt->ulNumBytesRead; |
128 | if (ulLen >= 18) { |
129 | /* Unpack the rm_file_hdr */ |
130 | pInt->fileHdr.id = rm_unpack32(&pBuf, &ulLen); |
131 | pInt->fileHdr.size = rm_unpack32(&pBuf, &ulLen); |
132 | pInt->fileHdr.version = rm_unpack16(&pBuf, &ulLen); |
133 | pInt->fileHdr.file_version = rm_unpack32(&pBuf, &ulLen); |
134 | pInt->fileHdr.num_headers = rm_unpack32(&pBuf, &ulLen); |
135 | /* Clear the return value */ |
136 | retVal = HXR_OK; |
137 | } else if (ulLen == 16) { |
138 | /* Unpack the rm_file_hdr */ |
139 | pInt->fileHdr.id = rm_unpack32(&pBuf, &ulLen); |
140 | pInt->fileHdr.size = rm_unpack32(&pBuf, &ulLen); |
141 | pInt->fileHdr.version = rm_unpack16(&pBuf, &ulLen); |
142 | if (pInt->fileHdr.version == 0) { |
143 | pInt->fileHdr.file_version = rm_unpack16(&pBuf, &ulLen); |
144 | pInt->fileHdr.num_headers = rm_unpack32(&pBuf, &ulLen); |
145 | /* Clear the return value */ |
146 | retVal = HXR_OK; |
147 | } |
148 | } |
149 | } |
150 | |
151 | return retVal; |
152 | } |
153 | |
154 | HX_RESULT rm_parseri_unpack_properties_hdr(rm_parser_internal* pInt) |
155 | { |
156 | HX_RESULT retVal = HXR_FAIL; |
157 | |
158 | if (pInt) { |
159 | /* Assign temporary variables */ |
160 | BYTE* pBuf = pInt->pReadBuffer; |
161 | UINT32 ulLen = pInt->ulNumBytesRead; |
162 | if (ulLen >= 50) { |
163 | /* Unpack the rm_properties_hdr */ |
164 | pInt->propHdr.id = rm_unpack32(&pBuf, &ulLen); |
165 | pInt->propHdr.size = rm_unpack32(&pBuf, &ulLen); |
166 | pInt->propHdr.version = rm_unpack16(&pBuf, &ulLen); |
167 | pInt->propHdr.max_bit_rate = rm_unpack32(&pBuf, &ulLen); |
168 | pInt->propHdr.avg_bit_rate = rm_unpack32(&pBuf, &ulLen); |
169 | pInt->propHdr.max_pkt_size = rm_unpack32(&pBuf, &ulLen); |
170 | pInt->propHdr.avg_pkt_size = rm_unpack32(&pBuf, &ulLen); |
171 | pInt->propHdr.num_pkts = rm_unpack32(&pBuf, &ulLen); |
172 | pInt->propHdr.duration = rm_unpack32(&pBuf, &ulLen); |
173 | pInt->propHdr.preroll = rm_unpack32(&pBuf, &ulLen); |
174 | pInt->propHdr.index_offset = rm_unpack32(&pBuf, &ulLen); |
175 | pInt->propHdr.data_offset = rm_unpack32(&pBuf, &ulLen); |
176 | pInt->propHdr.num_streams = rm_unpack16(&pBuf, &ulLen); |
177 | pInt->propHdr.flags = rm_unpack16(&pBuf, &ulLen); |
178 | /* Clear the return value */ |
179 | retVal = HXR_OK; |
180 | } |
181 | } |
182 | |
183 | return retVal; |
184 | } |
185 | |
186 | HX_RESULT rm_parseri_unpack_content_hdr(rm_parser_internal* pInt) |
187 | { |
188 | HX_RESULT retVal = HXR_FAIL; |
189 | |
190 | if (pInt) { |
191 | /* Assign temporary variables */ |
192 | BYTE* pBuf = pInt->pReadBuffer; |
193 | UINT32 ulLen = pInt->ulNumBytesRead; |
194 | if (ulLen >= 12) { |
195 | /* Unpack the rm_content_hdr */ |
196 | pInt->contHdr.id = rm_unpack32(&pBuf, &ulLen); |
197 | pInt->contHdr.size = rm_unpack32(&pBuf, &ulLen); |
198 | pInt->contHdr.version = rm_unpack16(&pBuf, &ulLen); |
199 | pInt->contHdr.title_sz = rm_unpack16(&pBuf, &ulLen); |
200 | if (ulLen >= (UINT32) pInt->contHdr.title_sz + 2) { |
201 | rm_unpack_string(&pBuf, &ulLen, pInt->contHdr.title_sz, |
202 | &pInt->contHdr.title, pInt->pUserMem, |
203 | pInt->fpMalloc, pInt->fpFree); |
204 | pInt->contHdr.author_sz = rm_unpack16(&pBuf, &ulLen); |
205 | if (ulLen >= (UINT32) pInt->contHdr.author_sz + 2) { |
206 | rm_unpack_string(&pBuf, &ulLen, pInt->contHdr.author_sz, |
207 | &pInt->contHdr.author, pInt->pUserMem, |
208 | pInt->fpMalloc, pInt->fpFree); |
209 | pInt->contHdr.copyright_sz = rm_unpack16(&pBuf, &ulLen); |
210 | if (ulLen >= (UINT32) pInt->contHdr.copyright_sz + 2) { |
211 | rm_unpack_string(&pBuf, &ulLen, pInt->contHdr.copyright_sz, |
212 | &pInt->contHdr.copyright, pInt->pUserMem, |
213 | pInt->fpMalloc, pInt->fpFree); |
214 | pInt->contHdr.comment_sz = rm_unpack16(&pBuf, &ulLen); |
215 | if (ulLen >= pInt->contHdr.comment_sz) { |
216 | rm_unpack_string(&pBuf, &ulLen, pInt->contHdr.comment_sz, |
217 | &pInt->contHdr.comment, pInt->pUserMem, |
218 | pInt->fpMalloc, pInt->fpFree); |
219 | if (ulLen >= 4) { |
220 | if (RM_DATA_OBJECT == rm_unpack32_nse(pBuf, ulLen)) { |
221 | rm_parseri_file_seek(pInt, pInt->ulCurFileOffset - ulLen, HX_SEEK_ORIGIN_SET); |
222 | } |
223 | } |
224 | /* Clear the return value */ |
225 | retVal = HXR_OK; |
226 | } |
227 | } |
228 | } |
229 | } |
230 | } |
231 | } |
232 | |
233 | return retVal; |
234 | } |
235 | |
236 | void rm_parseri_cleanup_content_hdr(rm_parser_internal* pInt) |
237 | { |
238 | if (pInt) { |
239 | /* Delete the title string */ |
240 | if (pInt->contHdr.title) { |
241 | rm_parseri_free(pInt, pInt->contHdr.title); |
242 | pInt->contHdr.title = HXNULL; |
243 | } |
244 | /* Delete the author string */ |
245 | if (pInt->contHdr.author) { |
246 | rm_parseri_free(pInt, pInt->contHdr.author); |
247 | pInt->contHdr.author = HXNULL; |
248 | } |
249 | /* Delete the copyright string */ |
250 | if (pInt->contHdr.copyright) { |
251 | rm_parseri_free(pInt, pInt->contHdr.copyright); |
252 | pInt->contHdr.copyright = HXNULL; |
253 | } |
254 | /* Delete the comment string */ |
255 | if (pInt->contHdr.comment) { |
256 | rm_parseri_free(pInt, pInt->contHdr.comment); |
257 | pInt->contHdr.comment = HXNULL; |
258 | } |
259 | } |
260 | } |
261 | |
262 | HX_RESULT rm_parseri_unpack_media_props_hdr(rm_parser_internal* pInt, |
263 | struct rm_media_props_hdr* h) |
264 | { |
265 | HX_RESULT retVal = HXR_FAIL; |
266 | |
267 | if (pInt && h) { |
268 | /* Assign temporary variables */ |
269 | BYTE* pBuf = pInt->pReadBuffer; |
270 | UINT32 ulLen = pInt->ulNumBytesRead; |
271 | /* Unpack the rm_media_props_hdr */ |
272 | if (ulLen >= 41) { |
273 | h->id = rm_unpack32(&pBuf, &ulLen); |
274 | h->size = rm_unpack32(&pBuf, &ulLen); |
275 | h->version = rm_unpack16(&pBuf, &ulLen); |
276 | h->stream_num = rm_unpack16(&pBuf, &ulLen); |
277 | h->max_bit_rate = rm_unpack32(&pBuf, &ulLen); |
278 | h->avg_bit_rate = rm_unpack32(&pBuf, &ulLen); |
279 | h->max_pkt_size = rm_unpack32(&pBuf, &ulLen); |
280 | h->avg_pkt_size = rm_unpack32(&pBuf, &ulLen); |
281 | h->start_time = rm_unpack32(&pBuf, &ulLen); |
282 | h->preroll = rm_unpack32(&pBuf, &ulLen); |
283 | h->duration = rm_unpack32(&pBuf, &ulLen); |
284 | h->stream_name_sz = rm_unpack8(&pBuf, &ulLen); |
285 | if (ulLen >= (UINT32) h->stream_name_sz + 1) { |
286 | rm_unpack_string(&pBuf, &ulLen, h->stream_name_sz, &h->stream_name, |
287 | pInt->pUserMem, pInt->fpMalloc, pInt->fpFree); |
288 | h->mime_type_sz = rm_unpack8(&pBuf, &ulLen); |
289 | if (ulLen >= (UINT32) h->mime_type_sz + 4) { |
290 | rm_unpack_string(&pBuf, &ulLen, h->mime_type_sz, &h->mime_type, |
291 | pInt->pUserMem, pInt->fpMalloc, pInt->fpFree); |
292 | h->type_spec_sz = rm_unpack32(&pBuf, &ulLen); |
293 | if (ulLen >= (UINT32) h->type_spec_sz) { |
294 | rm_unpack_buffer(&pBuf, &ulLen, h->type_spec_sz, &h->type_spec, |
295 | pInt->pUserMem, pInt->fpMalloc, pInt->fpFree); |
296 | /* Clear the return value */ |
297 | retVal = HXR_OK; |
298 | } |
299 | } |
300 | } |
301 | } |
302 | } |
303 | |
304 | return retVal; |
305 | } |
306 | |
307 | void rm_parseri_cleanup_media_props_hdr(rm_parser_internal* pInt, |
308 | struct rm_media_props_hdr* h) |
309 | { |
310 | if (pInt && h) { |
311 | /* Delete the stream name string */ |
312 | if (h->stream_name) { |
313 | rm_parseri_free(pInt, h->stream_name); |
314 | h->stream_name = HXNULL; |
315 | } |
316 | /* Delete the mime type string */ |
317 | if (h->mime_type) { |
318 | rm_parseri_free(pInt, h->mime_type); |
319 | h->mime_type = HXNULL; |
320 | } |
321 | /* Delete the type specific data buffer */ |
322 | if (h->type_spec) { |
323 | rm_parseri_free(pInt, h->type_spec); |
324 | h->type_spec = HXNULL; |
325 | } |
326 | } |
327 | } |
328 | |
329 | void rm_parseri_cleanup_all_media_props_hdrs(rm_parser_internal* pInt) |
330 | { |
331 | if (pInt && pInt->pMediaPropsHdr) { |
332 | /* Clean up each individual media properties header */ |
333 | UINT32 i = 0; |
334 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
335 | rm_parseri_cleanup_media_props_hdr(pInt, &pInt->pMediaPropsHdr[i]); |
336 | } |
337 | /* Free the memory for the array */ |
338 | rm_parseri_free(pInt, pInt->pMediaPropsHdr); |
339 | /* Zero out the number of media props headers */ |
340 | pInt->ulNumMediaPropsHdrs = 0; |
341 | pInt->ulNumMediaPropsHdrsAlloc = 0; |
342 | /* Null out the pointer */ |
343 | pInt->pMediaPropsHdr = HXNULL; |
344 | } |
345 | } |
346 | |
347 | HX_RESULT rm_parseri_unpack_name_value_map(rm_parser_internal* pInt, |
348 | struct rm_name_value_map* pMap, |
349 | BYTE** ppBuf, UINT32* pulLen) |
350 | { |
351 | HX_RESULT retVal = HXR_FAIL; |
352 | |
353 | if (pInt && pMap && ppBuf && pulLen && *pulLen >= 7) { |
354 | /* Unpack the name-value map struct */ |
355 | pMap->size = rm_unpack32(ppBuf, pulLen); |
356 | pMap->version = rm_unpack16(ppBuf, pulLen); |
357 | pMap->name_sz = rm_unpack8(ppBuf, pulLen); |
358 | if (*pulLen >= (UINT32) pMap->name_sz + 6) { |
359 | rm_unpack_string(ppBuf, pulLen, pMap->name_sz, &pMap->name, |
360 | pInt->pUserMem, pInt->fpMalloc, pInt->fpFree); |
361 | pMap->type = rm_unpack32(ppBuf, pulLen); |
362 | pMap->value_sz = rm_unpack16(ppBuf, pulLen); |
363 | if (*pulLen >= pMap->value_sz) { |
364 | rm_unpack_buffer(ppBuf, pulLen, pMap->value_sz, &pMap->value, |
365 | pInt->pUserMem, pInt->fpMalloc, pInt->fpFree); |
366 | /* Clear the return value */ |
367 | retVal = HXR_OK; |
368 | } |
369 | } |
370 | } |
371 | |
372 | return retVal; |
373 | } |
374 | |
375 | void rm_parseri_cleanup_name_value_map(rm_parser_internal* pInt, |
376 | struct rm_name_value_map* h) |
377 | { |
378 | if (pInt && h) { |
379 | /* Delete the name string */ |
380 | if (h->name) { |
381 | rm_parseri_free(pInt, h->name); |
382 | h->name = HXNULL; |
383 | } |
384 | /* Delete the value buffer */ |
385 | if (h->value) { |
386 | rm_parseri_free(pInt, h->value); |
387 | h->value = HXNULL; |
388 | } |
389 | } |
390 | } |
391 | |
392 | void rm_parseri_cleanup_all_name_value_maps(rm_parser_internal* pInt, |
393 | struct rm_logical_stream_hdr* h) |
394 | { |
395 | if (pInt && h && h->props) { |
396 | /* Clean up each name-value pair */ |
397 | UINT16 i = 0; |
398 | for (i = 0; i < h->num_props; i++) { |
399 | rm_parseri_cleanup_name_value_map(pInt, &h->props[i]); |
400 | } |
401 | /* Free the array of props */ |
402 | rm_parseri_free(pInt, h->props); |
403 | /* Zero out the number of props */ |
404 | h->num_props = 0; |
405 | /* NULL out the pointer */ |
406 | h->props = HXNULL; |
407 | } |
408 | } |
409 | |
410 | HX_RESULT rm_parseri_unpack_logical_stream_hdr(rm_parser_internal* pInt, |
411 | struct rm_media_props_hdr* mh, |
412 | struct rm_logical_stream_hdr* h) |
413 | { |
414 | HX_RESULT retVal = HXR_FAIL; |
415 | |
416 | if (pInt && mh && mh->type_spec && mh->type_spec_sz > 0 && h) { |
417 | /* Assign temporary variables */ |
418 | BYTE* pBuf = mh->type_spec; |
419 | UINT32 ulLen = mh->type_spec_sz; |
420 | UINT32 ulSize = 0; |
421 | UINT16 i = 0; |
422 | /* Parse the logical stream header */ |
423 | if (ulLen >= 8) { |
424 | h->size = rm_unpack32(&pBuf, &ulLen); |
425 | h->version = rm_unpack16(&pBuf, &ulLen); |
426 | h->num_physical_streams = rm_unpack16(&pBuf, &ulLen); |
427 | if (ulLen >= (UINT32) 6 * h->num_physical_streams + 2) { |
428 | rm_unpack_array(&pBuf, &ulLen, h->num_physical_streams, sizeof(UINT16), |
429 | (void**) &h->physical_stream_num, pInt->pUserMem, |
430 | pInt->fpMalloc, pInt->fpFree); |
431 | rm_unpack_array(&pBuf, &ulLen, h->num_physical_streams, sizeof(UINT32), |
432 | (void**) &h->data_offsets, pInt->pUserMem, |
433 | pInt->fpMalloc, pInt->fpFree); |
434 | h->num_rules = rm_unpack16(&pBuf, &ulLen); |
435 | if (ulLen >= (UINT32) h->num_rules * 2 + 2) { |
436 | rm_unpack_array(&pBuf, &ulLen, h->num_rules, sizeof(UINT16), |
437 | (void**) &h->rule_stream_map, pInt->pUserMem, |
438 | pInt->fpMalloc, pInt->fpFree); |
439 | h->num_props = rm_unpack16(&pBuf, &ulLen); |
440 | /* Clean up any existing name-value pairs */ |
441 | rm_parseri_cleanup_all_name_value_maps(pInt, h); |
442 | /* Allocate an array of name value pairs */ |
443 | ulSize = h->num_props * sizeof(struct rm_name_value_map); |
444 | if (ulSize) { |
445 | h->props = (struct rm_name_value_map*) rm_parseri_malloc(pInt, ulSize); |
446 | if (h->props) { |
447 | /* NULL out the memory */ |
448 | memset(h->props, 0, ulSize); |
449 | /* Clear the return value */ |
450 | retVal = HXR_OK; |
451 | /* Unpack each of the name-value pairs */ |
452 | for (i = 0; i < h->num_props && retVal == HXR_OK; i++) { |
453 | retVal = rm_parseri_unpack_name_value_map(pInt, &h->props[i], |
454 | &pBuf, &ulLen); |
455 | } |
456 | } |
457 | } else { |
458 | /* No properties - not an error */ |
459 | retVal = HXR_OK; |
460 | } |
461 | } |
462 | } |
463 | } |
464 | } |
465 | |
466 | return retVal; |
467 | } |
468 | |
469 | UINT32 rm_parseri_get_num_logical_streams(rm_parser_internal* pInt) |
470 | { |
471 | UINT32 ulRet = 0; |
472 | |
473 | if (pInt && pInt->pMediaPropsHdr) { |
474 | UINT32 i = 0; |
475 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
476 | const char* pszMimeType = (const char*) pInt->pMediaPropsHdr[i].mime_type; |
477 | if (rm_parseri_is_logical_stream_mime_type(pszMimeType)) { |
478 | ulRet++; |
479 | } |
480 | } |
481 | } |
482 | |
483 | return ulRet; |
484 | } |
485 | |
486 | HXBOOL rm_parseri_is_logical_fileinfo_present(rm_parser_internal* pInt, UINT32* pulIndx) |
487 | { |
488 | HXBOOL bRet = FALSE; |
489 | |
490 | if (pInt && pInt->pMediaPropsHdr && pulIndx) { |
491 | UINT32 i = 0; |
492 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
493 | const char* pszMimeType = (const char*) pInt->pMediaPropsHdr[i].mime_type; |
494 | if (rm_parseri_is_logical_fileinfo_mime_type(pszMimeType)) { |
495 | bRet = TRUE; |
496 | *pulIndx = i; |
497 | break; |
498 | } |
499 | } |
500 | } |
501 | |
502 | return bRet; |
503 | } |
504 | |
505 | void rm_parseri_cleanup_logical_fileinfo_hdr(rm_parser_internal* pInt) |
506 | { |
507 | if (pInt && pInt->pLogicalFileInfo) { |
508 | /* Clean up the struct */ |
509 | rm_parseri_cleanup_logical_stream_hdr(pInt, pInt->pLogicalFileInfo); |
510 | /* Free the struct memory */ |
511 | rm_parseri_free(pInt, pInt->pLogicalFileInfo); |
512 | /* NULL out the pointer */ |
513 | pInt->pLogicalFileInfo = HXNULL; |
514 | } |
515 | } |
516 | |
517 | HX_RESULT rm_parseri_unpack_all_logical_stream_hdrs(rm_parser_internal* pInt) |
518 | { |
519 | HX_RESULT retVal = HXR_FAIL; |
520 | |
521 | if (pInt) { |
522 | /* Declare some local variables we need later */ |
523 | UINT32 ulSize = 0; |
524 | UINT32 ulIndx = 0; |
525 | UINT32 i = 0; |
526 | /* Get the number of media props headers that are logical streams */ |
527 | UINT32 ulNumLogical = rm_parseri_get_num_logical_streams(pInt); |
528 | if (ulNumLogical) { |
529 | /* Free any existing logical stream array */ |
530 | rm_parseri_cleanup_all_logical_stream_hdrs(pInt); |
531 | /* Compute the size of the logical stream header array */ |
532 | ulSize = ulNumLogical * sizeof(struct rm_logical_stream_hdr); |
533 | /* Allocate the array of logical stream headers */ |
534 | pInt->pLogicalStreamHdr = |
535 | (struct rm_logical_stream_hdr*) rm_parseri_malloc(pInt, ulSize); |
536 | if (pInt->pLogicalStreamHdr) { |
537 | /* Zero out the memory */ |
538 | memset(pInt->pLogicalStreamHdr, 0, ulSize); |
539 | /* Assign the number of logical stream headers */ |
540 | pInt->ulNumLogicalStreamHdrs = ulNumLogical; |
541 | /* Clear the return value */ |
542 | retVal = HXR_OK; |
543 | /* |
544 | * Loop through all the media properties headers, and |
545 | * if a header is a logical stream, then unpack it |
546 | */ |
547 | for (i = 0; i < pInt->ulNumMediaPropsHdrs && retVal == HXR_OK; i++) { |
548 | const char* pszMimeType = (const char*) pInt->pMediaPropsHdr[i].mime_type; |
549 | if (rm_parseri_is_logical_stream_mime_type(pszMimeType)) { |
550 | /* |
551 | * Unpack the logical stream. We don't have |
552 | * to worry about ulIndx being less than |
553 | * ulNumLogicalStreamHdrs since we already |
554 | * guaranteed above that ulNumLogicalStreamHdrs |
555 | * was correct. |
556 | */ |
557 | retVal = rm_parseri_unpack_logical_stream_hdr(pInt, |
558 | &pInt->pMediaPropsHdr[i], |
559 | &pInt->pLogicalStreamHdr[ulIndx]); |
560 | if (retVal == HXR_OK) { |
561 | ulIndx++; |
562 | } else { |
563 | /* Call back to the error interface */ |
564 | rm_parseri_error(pInt, retVal, "Failed to parse logical stream header."); |
565 | } |
566 | } |
567 | } |
568 | } |
569 | } else { |
570 | /* No logical streams - single-rate file */ |
571 | retVal = HXR_OK; |
572 | } |
573 | if (retVal == HXR_OK) { |
574 | /* Clean up any existing logical-fileinfo header */ |
575 | rm_parseri_cleanup_logical_fileinfo_hdr(pInt); |
576 | /* Do we have a logical-fileinfo header? */ |
577 | if (rm_parseri_is_logical_fileinfo_present(pInt, &ulIndx)) { |
578 | /* Compute the size of the logical fileinfo */ |
579 | ulSize = sizeof(struct rm_logical_stream_hdr); |
580 | /* Allocate space for the struct */ |
581 | pInt->pLogicalFileInfo = |
582 | (struct rm_logical_stream_hdr*) rm_parseri_malloc(pInt, ulSize); |
583 | if (pInt->pLogicalFileInfo) { |
584 | /* Zero out the memory */ |
585 | memset(pInt->pLogicalFileInfo, 0, ulSize); |
586 | /* Unpack the logical-fileinfo struct */ |
587 | retVal = rm_parseri_unpack_logical_stream_hdr(pInt, |
588 | &pInt->pMediaPropsHdr[ulIndx], |
589 | pInt->pLogicalFileInfo); |
590 | if (retVal != HXR_OK) { |
591 | /* Call back to the error interface */ |
592 | rm_parseri_error(pInt, retVal, "Failed to parse logical-fileinfo header."); |
593 | } |
594 | } else { |
595 | retVal = HXR_OUTOFMEMORY; |
596 | } |
597 | } |
598 | } |
599 | } |
600 | |
601 | return retVal; |
602 | } |
603 | |
604 | void rm_parseri_cleanup_logical_stream_hdr(rm_parser_internal* pInt, |
605 | struct rm_logical_stream_hdr* h) |
606 | { |
607 | if (pInt && h) { |
608 | /* Delete the stream number array */ |
609 | if (h->physical_stream_num) { |
610 | rm_parseri_free(pInt, h->physical_stream_num); |
611 | h->physical_stream_num = HXNULL; |
612 | } |
613 | /* Delete the data offsets array */ |
614 | if (h->data_offsets) { |
615 | rm_parseri_free(pInt, h->data_offsets); |
616 | h->data_offsets = HXNULL; |
617 | } |
618 | /* Delete the rule-to-stream map */ |
619 | if (h->rule_stream_map) { |
620 | rm_parseri_free(pInt, h->rule_stream_map); |
621 | h->rule_stream_map = HXNULL; |
622 | } |
623 | /* Clean up the logical stream props */ |
624 | rm_parseri_cleanup_all_name_value_maps(pInt, h); |
625 | } |
626 | } |
627 | |
628 | void rm_parseri_cleanup_all_logical_stream_hdrs(rm_parser_internal* pInt) |
629 | { |
630 | if (pInt && pInt->pLogicalStreamHdr) { |
631 | /* Clean up the individual logical stream headers */ |
632 | UINT32 i = 0; |
633 | for (i = 0; i < pInt->ulNumLogicalStreamHdrs; i++) { |
634 | rm_parseri_cleanup_logical_stream_hdr(pInt, &pInt->pLogicalStreamHdr[i]); |
635 | } |
636 | /* Free the memory of the array */ |
637 | rm_parseri_free(pInt, pInt->pLogicalStreamHdr); |
638 | /* NULL out the array pointer */ |
639 | pInt->pLogicalStreamHdr = HXNULL; |
640 | /* Zero out the array size and number of headers */ |
641 | pInt->ulNumLogicalStreamHdrs = 0; |
642 | } |
643 | } |
644 | |
645 | HX_RESULT rm_parseri_allocate_media_props_hdrs(rm_parser_internal* pInt) |
646 | { |
647 | HX_RESULT retVal = HXR_OUTOFMEMORY; |
648 | |
649 | if (pInt) { |
650 | UINT32 ulSize = 0; |
651 | /* Clean up any existing media properties header array */ |
652 | rm_parseri_cleanup_all_media_props_hdrs(pInt); |
653 | /* |
654 | * Compute the number of stream properties headers |
655 | * we need to allocate. Normally this is propHdr.num_streams, |
656 | * but for file version > 0, it is possible to have file-info |
657 | * header for each stream but not all of them may be present. |
658 | */ |
659 | pInt->ulNumMediaPropsHdrsAlloc = pInt->propHdr.num_streams; |
660 | if (pInt->fileHdr.file_version != 0) { |
661 | if (pInt->ulNumMediaPropsHdrsAlloc > 2) { |
662 | pInt->ulNumMediaPropsHdrsAlloc = (pInt->ulNumMediaPropsHdrsAlloc - 1) * 2; |
663 | } |
664 | } |
665 | /* Calculate the size of the stream property header array */ |
666 | ulSize = pInt->ulNumMediaPropsHdrsAlloc * sizeof(struct rm_media_props_hdr); |
667 | /* Allocate the number of media properties headers */ |
668 | pInt->pMediaPropsHdr = |
669 | (struct rm_media_props_hdr*) rm_parseri_malloc(pInt, ulSize); |
670 | if (pInt->pMediaPropsHdr) { |
671 | /* NULL out the memory */ |
672 | memset((void*) pInt->pMediaPropsHdr, 0, ulSize); |
673 | /* Clear the return value */ |
674 | retVal = HXR_OK; |
675 | } |
676 | } |
677 | |
678 | return retVal; |
679 | } |
680 | |
681 | void rm_parseri_cleanup_read_buffer(rm_parser_internal* pInt) |
682 | { |
683 | if (pInt && pInt->pReadBuffer) { |
684 | rm_parseri_free(pInt, pInt->pReadBuffer); |
685 | pInt->pReadBuffer = HXNULL; |
686 | pInt->ulReadBufferSize = 0; |
687 | pInt->ulNumBytesRead = 0; |
688 | } |
689 | } |
690 | |
691 | UINT32 rm_parseri_get_media_props_hdr_stream_num(rm_parser_internal* pInt) |
692 | { |
693 | UINT32 ulRet = 0; |
694 | |
695 | if (pInt && pInt->pReadBuffer && pInt->ulNumBytesRead >= 12) { |
696 | /* Assign temporary variables */ |
697 | BYTE* pBuf = pInt->pReadBuffer; |
698 | UINT32 ulLen = pInt->ulNumBytesRead; |
699 | /* Skip directly to the stream_num */ |
700 | pBuf += 10; |
701 | ulLen -= 10; |
702 | /* Unpack the stream_num. */ |
703 | ulRet = (UINT32) rm_unpack16(&pBuf, &ulLen); |
704 | } |
705 | |
706 | return ulRet; |
707 | } |
708 | |
709 | HXBOOL rm_parseri_is_logical_stream_mime_type(const char* pszMimeType) |
710 | { |
711 | HXBOOL bRet = FALSE; |
712 | |
713 | if (pszMimeType) { |
714 | if (!rm_parseri_is_logical_fileinfo_mime_type(pszMimeType)) { |
715 | if (!strncmp(pszMimeType, RM_PARSER_LOGICAL_PREFIX, |
716 | strlen(RM_PARSER_LOGICAL_PREFIX))) { |
717 | bRet = TRUE; |
718 | } |
719 | } |
720 | } |
721 | |
722 | return bRet; |
723 | } |
724 | |
725 | HXBOOL rm_parseri_is_logical_fileinfo_mime_type(const char* pszMimeType) |
726 | { |
727 | HXBOOL bRet = FALSE; |
728 | |
729 | if (pszMimeType) { |
730 | if (!strcmp(pszMimeType, RM_PARSER_LOGICAL_FILEINFO)) { |
731 | bRet = TRUE; |
732 | } |
733 | } |
734 | |
735 | return bRet; |
736 | } |
737 | |
738 | HX_RESULT rm_parseri_read_next_header(rm_parser_internal* pInt, UINT32* pulID) |
739 | { |
740 | HX_RESULT retVal = HXR_UNEXPECTED; |
741 | if (pInt && pulID) { |
742 | struct rm_generic_hdr genHdr; |
743 | UINT32 ulHeaderSize = 0; |
744 | UINT32 ulBytesToRead = 0; |
745 | UINT32 ulNumBytesRead = 0; |
746 | /* Set the return value */ |
747 | retVal = HXR_READ_ERROR; |
748 | /* Read a generic header into the read buffer */ |
749 | ulBytesToRead = RM_PARSER_GENERIC_HDR_SIZE; |
750 | ulNumBytesRead = rm_parseri_file_read(pInt, ulBytesToRead, 0); |
751 | /* Make sure we read enough */ |
752 | if (ulNumBytesRead == ulBytesToRead) { |
753 | /* Unpack a generic header */ |
754 | rm_parseri_unpack_generic_hdr(pInt, &genHdr); |
755 | /* |
756 | * Compute the size of the header. For |
757 | * most header types, this will be the size specified |
758 | * in the "size" field. However, for data chunk headers and |
759 | * index chunk headers, the "size" also includes the CONTENTS |
760 | * of the chunk (all the packets or all the index records). |
761 | * So for those chunks we must special case them. |
762 | */ |
763 | ulHeaderSize = genHdr.size; |
764 | if (genHdr.id == RM_DATA_OBJECT) { |
765 | ulHeaderSize = RM_PARSER_DATA_CHUNK_HEADER_SIZE; |
766 | } else if (genHdr.id == RM_INDEX_OBJECT) { |
767 | ulHeaderSize = RM_PARSER_INDEX_HEADER_SIZE; |
768 | } |
769 | /* Now compute how many bytes we still need to read */ |
770 | if (ulHeaderSize > RM_PARSER_GENERIC_HDR_SIZE) { |
771 | /* some incomplete downloaded file filled with 0xffffffff by downloader */ |
772 | if (ulHeaderSize != 0xffffffff) { |
773 | ulBytesToRead = ulHeaderSize - RM_PARSER_GENERIC_HDR_SIZE; |
774 | /* Read the rest of the chunk */ |
775 | ulNumBytesRead = rm_parseri_file_read(pInt, ulBytesToRead, RM_PARSER_GENERIC_HDR_SIZE); |
776 | if (ulNumBytesRead == ulBytesToRead) { |
777 | /* Assign the header id to the out parameter */ |
778 | *pulID = genHdr.id; |
779 | /* Clear the return value */ |
780 | retVal = HXR_OK; |
781 | } else { |
782 | /* Call back to error interface */ |
783 | rm_parseri_error(pInt, retVal, "Could not read chunk data."); |
784 | } |
785 | } else { |
786 | /* Call back to error interface */ |
787 | rm_parseri_error(pInt, retVal, "Could not read chunk data."); |
788 | } |
789 | } |
790 | } else { |
791 | /* Call back to error interface */ |
792 | rm_parseri_error(pInt, retVal, "Could not read chunk header."); |
793 | } |
794 | } |
795 | |
796 | return retVal; |
797 | } |
798 | |
799 | HX_RESULT rm_parseri_read_next_packet_header(rm_parser_internal* pInt, |
800 | struct rm_pkt_hdr* pPktHdr) |
801 | { |
802 | HX_RESULT retVal = HXR_UNEXPECTED; |
803 | |
804 | if (pInt) { |
805 | UINT32 ulNumBytesRead = 0; |
806 | /* Change the error return */ |
807 | retVal = HXR_READ_ERROR; |
808 | /* Read the packet header into the read buffer */ |
809 | ulNumBytesRead = rm_parseri_file_read(pInt, RM_PARSER_PACKET_HEADER_SIZE, 0); |
810 | if (ulNumBytesRead == RM_PARSER_PACKET_HEADER_SIZE) { |
811 | /* Unpack the packet header */ |
812 | retVal = rm_parseri_unpack_pkt_hdr(pInt, pPktHdr); |
813 | } else { |
814 | /* Call back to error interface */ |
815 | rm_parseri_error(pInt, retVal, "Could not read packet header."); |
816 | } |
817 | } |
818 | |
819 | return retVal; |
820 | } |
821 | |
822 | HX_RESULT rm_parseri_setup_interleaved_streams(rm_parser_internal* pInt) |
823 | { |
824 | HX_RESULT retVal = HXR_NOT_SUPPORTED; |
825 | |
826 | if (pInt && pInt->pMediaPropsHdr && pInt->ulNumMediaPropsHdrs) { |
827 | /* Declare some locals we'll need later */ |
828 | struct rm_media_props_hdr* pTmp = HXNULL; |
829 | UINT32 ulNumInterleaved = 0; |
830 | /* Allocate a temporary array of HXBOOLs */ |
831 | UINT32 ulSize = pInt->ulNumMediaPropsHdrs * sizeof(HXBOOL); |
832 | HXBOOL* pInterleaved = (HXBOOL*) rm_parseri_malloc(pInt, ulSize); |
833 | if (pInterleaved) { |
834 | /* Init them all the TRUE */ |
835 | UINT32 i = 0; |
836 | UINT32 j = 0; |
837 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
838 | pInterleaved[i] = TRUE; |
839 | } |
840 | /* |
841 | * Now run through the all the logical streams |
842 | * and remove the physical streams |
843 | */ |
844 | for (i = 0; i < pInt->ulNumLogicalStreamHdrs; i++) { |
845 | for (j = 0; j < (UINT32) pInt->pLogicalStreamHdr[i].num_physical_streams; j++) { |
846 | pInterleaved[pInt->pLogicalStreamHdr[i].physical_stream_num[j]] = FALSE; |
847 | } |
848 | } |
849 | /* |
850 | * Now remove the media props headers that |
851 | * are actually logical stream and logical fileinfo headers. |
852 | */ |
853 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
854 | const char* pszMimeType = (const char*) pInt->pMediaPropsHdr[i].mime_type; |
855 | if (rm_parseri_is_logical_stream_mime_type(pszMimeType) || |
856 | rm_parseri_is_logical_fileinfo_mime_type(pszMimeType)) { |
857 | pInterleaved[i] = FALSE; |
858 | } |
859 | } |
860 | /* Now count the interleaved streams */ |
861 | ulNumInterleaved = 0; |
862 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
863 | if (pInterleaved[i]) { |
864 | ulNumInterleaved++; |
865 | } |
866 | } |
867 | /* Do we have any interleaved streams? */ |
868 | if (ulNumInterleaved) { |
869 | /* Allocate a new array of media props headers */ |
870 | retVal = HXR_OUTOFMEMORY; |
871 | ulSize = ulNumInterleaved * sizeof(struct rm_media_props_hdr); |
872 | pTmp = (struct rm_media_props_hdr*) rm_parseri_malloc(pInt, ulSize); |
873 | if (pTmp) { |
874 | /* Copy the media props headers which are interleaved */ |
875 | j = 0; |
876 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
877 | if (pInterleaved[i]) { |
878 | pInt->pMediaPropsHdr[i].start_offset = pInt->propHdr.data_offset; |
879 | pTmp[j++] = pInt->pMediaPropsHdr[i]; |
880 | } else { |
881 | rm_parseri_cleanup_media_props_hdr(pInt, &pInt->pMediaPropsHdr[i]); |
882 | } |
883 | } |
884 | /* Free the logical stream array. */ |
885 | rm_parseri_cleanup_all_logical_stream_hdrs(pInt); |
886 | /* Delete the memory associated with the old media props array */ |
887 | rm_parseri_free(pInt, pInt->pMediaPropsHdr); |
888 | /* Replace the old media props array with the new one */ |
889 | pInt->pMediaPropsHdr = pTmp; |
890 | /* Update the number of media props headers */ |
891 | pInt->ulNumMediaPropsHdrs = ulNumInterleaved; |
892 | pInt->ulNumMediaPropsHdrsAlloc = ulNumInterleaved; |
893 | /* Update the number of streams */ |
894 | pInt->ulNumStreams = ulNumInterleaved; |
895 | /* Clear the return value */ |
896 | retVal = HXR_OK; |
897 | } |
898 | } |
899 | } |
900 | /* Free the temporary array */ |
901 | rm_parseri_free(pInt, pInterleaved); |
902 | } |
903 | |
904 | return retVal; |
905 | } |
906 | |
907 | HX_RESULT rm_parseri_unpack_logical_multirate_type_spec(rm_parser_internal* pInt, UINT32 index) |
908 | { |
909 | HX_RESULT retVal = HXR_NOT_SUPPORTED; |
910 | UINT16 *pStreamNum; |
911 | unsigned char *pOffset; |
912 | UINT16 num_stream = 0; |
913 | int w = 0xFF; /* For run-time endianness detection */ |
914 | int i, j; |
915 | UINT16 stream_num; |
916 | UINT32 start_offset; |
917 | |
918 | if (pInt->pMediaPropsHdr[index].type_spec) { |
919 | memcpy(&num_stream, pInt->pMediaPropsHdr[index].type_spec + 6, sizeof(UINT16)); |
920 | num_stream = IS_BIG_ENDIAN(w) ? num_stream : BYTE_SWAP_UINT16(num_stream); |
921 | if (num_stream) { |
922 | pStreamNum = (UINT16*)(pInt->pMediaPropsHdr[index].type_spec + 8); |
923 | pOffset = (unsigned char*)(pInt->pMediaPropsHdr[index].type_spec + 8 + num_stream * sizeof(UINT16)); |
924 | for (i = 0; i < num_stream; i++) { |
925 | memcpy(&stream_num, pStreamNum, sizeof(UINT16)); |
926 | stream_num = IS_BIG_ENDIAN(w) ? stream_num : BYTE_SWAP_UINT16(stream_num); |
927 | for (j = 0; j < pInt->ulNumMediaPropsHdrs; j++) { |
928 | if (pInt->pMediaPropsHdr[j].stream_num == stream_num) { |
929 | memcpy((char*)&start_offset, (char*)pOffset, sizeof(UINT32)); |
930 | pInt->pMediaPropsHdr[j].start_offset = IS_BIG_ENDIAN(w) ? start_offset : BYTE_SWAP_UINT32(start_offset); |
931 | break; |
932 | } |
933 | } |
934 | pStreamNum++; |
935 | pOffset += 4; |
936 | } |
937 | retVal = HXR_OK; |
938 | } |
939 | } |
940 | return retVal; |
941 | } |
942 | |
943 | HX_RESULT rm_parseri_setup_multirate_streams(rm_parser_internal* pInt) |
944 | { |
945 | HX_RESULT retVal = HXR_NOT_SUPPORTED; |
946 | |
947 | if (pInt && pInt->pMediaPropsHdr && pInt->ulNumMediaPropsHdrs) { |
948 | /* Declare some locals we'll need later */ |
949 | struct rm_media_props_hdr* pTmp = HXNULL; |
950 | UINT32 ulNumInterleaved = 0; |
951 | /* Allocate a temporary array of HXBOOLs */ |
952 | UINT32 ulSize = pInt->ulNumMediaPropsHdrs * sizeof(HXBOOL); |
953 | HXBOOL* pInterleaved = (HXBOOL*) rm_parseri_malloc(pInt, ulSize); |
954 | if (pInterleaved) { |
955 | UINT32 i = 0; |
956 | UINT32 j = 0; |
957 | /* |
958 | * Now get info from logical headers. |
959 | */ |
960 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
961 | const char* pszMimeType = (const char*) pInt->pMediaPropsHdr[i].mime_type; |
962 | if ((!strcmp(pszMimeType, RM_PARSER_LOGICAL_MULTIRATE_VIDEO)) || |
963 | (!strcmp(pszMimeType, RM_PARSER_LOGICAL_MULTIRATE_AUDIO))) { |
964 | rm_parseri_unpack_logical_multirate_type_spec(pInt, i); |
965 | } |
966 | } |
967 | /* |
968 | * Now remove the media props headers that |
969 | * are actually logical stream and logical fileinfo headers. |
970 | */ |
971 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
972 | const char* pszMimeType = (const char*) pInt->pMediaPropsHdr[i].mime_type; |
973 | if (rm_stream_is_realaudio_mimetype(pszMimeType) || |
974 | rm_stream_is_realvideo_mimetype(pszMimeType)) { |
975 | pInterleaved[i] = TRUE; |
976 | ulNumInterleaved++; |
977 | } else { |
978 | pInterleaved[i] = FALSE; |
979 | } |
980 | } |
981 | |
982 | /* Do we have any streams? */ |
983 | if (ulNumInterleaved > 0) { |
984 | /* Allocate a new array of media props headers */ |
985 | retVal = HXR_OUTOFMEMORY; |
986 | ulSize = ulNumInterleaved * sizeof(struct rm_media_props_hdr); |
987 | pTmp = (struct rm_media_props_hdr*) rm_parseri_malloc(pInt, ulSize); |
988 | if (pTmp) { |
989 | /* Copy the media props headers which are interleaved */ |
990 | j = 0; |
991 | for (i = 0; i < pInt->ulNumMediaPropsHdrs; i++) { |
992 | if (pInterleaved[i]) { |
993 | pTmp[j++] = pInt->pMediaPropsHdr[i]; |
994 | } else { |
995 | rm_parseri_cleanup_media_props_hdr(pInt, &pInt->pMediaPropsHdr[i]); |
996 | } |
997 | } |
998 | /* Free the logical stream array. */ |
999 | rm_parseri_cleanup_all_logical_stream_hdrs(pInt); |
1000 | /* Delete the memory associated with the old media props array */ |
1001 | rm_parseri_free(pInt, pInt->pMediaPropsHdr); |
1002 | /* Replace the old media props array with the new one */ |
1003 | pInt->pMediaPropsHdr = pTmp; |
1004 | /* Update the number of media props headers */ |
1005 | pInt->ulNumMediaPropsHdrs = ulNumInterleaved; |
1006 | pInt->ulNumMediaPropsHdrsAlloc = ulNumInterleaved; |
1007 | /* Update the number of streams */ |
1008 | pInt->ulNumStreams = ulNumInterleaved; |
1009 | /* Clear the return value */ |
1010 | retVal = HXR_OK; |
1011 | } |
1012 | } |
1013 | } |
1014 | /* Free the temporary array */ |
1015 | rm_parseri_free(pInt, pInterleaved); |
1016 | } |
1017 | |
1018 | return retVal; |
1019 | } |
1020 | |
1021 | HX_RESULT rm_parseri_read_all_headers(rm_parser_internal* pInt) |
1022 | { |
1023 | HX_RESULT retVal = HXR_FAIL; |
1024 | |
1025 | if (pInt) { |
1026 | /* Declare the chunk id local variable */ |
1027 | UINT32 ulID = 0; |
1028 | /* Seek back to the beginning of the file */ |
1029 | rm_parseri_file_seek(pInt, 0, HX_SEEK_ORIGIN_SET); |
1030 | /* Read the first header */ |
1031 | retVal = rm_parseri_read_next_header(pInt, &ulID); |
1032 | if (retVal == HXR_OK) { |
1033 | /* |
1034 | * If we don't encounter a RM_HEADER_OBJECT at the |
1035 | * beginning of the file, then that's a problem. |
1036 | */ |
1037 | if (ulID == RM_HEADER_OBJECT) { |
1038 | /* Unpack the .rm file header */ |
1039 | retVal = rm_parseri_unpack_file_hdr(pInt); |
1040 | if (retVal == HXR_OK) { |
1041 | /* |
1042 | * Check the version of this file header struct |
1043 | * as well as the file_version to make sure we |
1044 | * support this version of the .rm file. |
1045 | */ |
1046 | if ((pInt->fileHdr.version == 0 || pInt->fileHdr.version == 1) && |
1047 | (pInt->fileHdr.file_version == 0 || pInt->fileHdr.file_version == 1)) { |
1048 | /* |
1049 | * Now loop and unpack until we have either unpacked |
1050 | * the number of headers specified in the file header |
1051 | * or we reach the first data chunk. |
1052 | */ |
1053 | HXBOOL bDone = FALSE; |
1054 | UINT32 i = 0; |
1055 | for (i = 0; i < pInt->fileHdr.num_headers && !bDone && retVal == HXR_OK; i++) { |
1056 | /* Read the next header into the read buffer */ |
1057 | retVal = rm_parseri_read_next_header(pInt, &ulID); |
1058 | if (retVal == HXR_OK) { |
1059 | /* Switch based on chunk 4cc */ |
1060 | switch (ulID) { |
1061 | case RM_PROPERTIES_OBJECT: { |
1062 | /* Unpack the clip properties header */ |
1063 | retVal = rm_parseri_unpack_properties_hdr(pInt); |
1064 | if (retVal == HXR_OK) { |
1065 | /* Allocate the media props array */ |
1066 | retVal = rm_parseri_allocate_media_props_hdrs(pInt); |
1067 | if (retVal == HXR_OK) { |
1068 | /* Init the number of media props headers we've seen */ |
1069 | pInt->ulNumMediaPropsHdrs = 0; |
1070 | } |
1071 | } |
1072 | } |
1073 | break; |
1074 | case RM_MEDIA_PROPERTIES_OBJECT: { |
1075 | /* |
1076 | * Media properties headers aren't necessarily |
1077 | * ordered in the file by stream_num. However, we would like |
1078 | * be able to index them by stream_num. Therefore, we will |
1079 | * first parse out the stream_num member and then place |
1080 | * it in the array at that index. |
1081 | */ |
1082 | UINT32 ulStreamNum = rm_parseri_get_media_props_hdr_stream_num(pInt); |
1083 | if (ulStreamNum < pInt->ulNumMediaPropsHdrsAlloc) { |
1084 | /* Unpack the media properties header */ |
1085 | retVal = rm_parseri_unpack_media_props_hdr(pInt, &pInt->pMediaPropsHdr[ulStreamNum]); |
1086 | /* Increment the number of properties we've read */ |
1087 | if (retVal == HXR_OK) { |
1088 | /* Increment the number of media props headers we've seen */ |
1089 | pInt->ulNumMediaPropsHdrs++; |
1090 | } else { |
1091 | /* Parsing of media props header failed. */ |
1092 | retVal = HXR_CORRUPT_FILE; |
1093 | /* Call back to the error interface */ |
1094 | rm_parseri_error(pInt, retVal, "Failed to parse media props header - possibly a corrupt file."); |
1095 | } |
1096 | } else { |
1097 | /* Illegal stream number */ |
1098 | retVal = HXR_CORRUPT_FILE; |
1099 | /* Call back to the error interface */ |
1100 | rm_parseri_error(pInt, retVal, "Illegal stream number - possibly a corrupt file."); |
1101 | } |
1102 | } |
1103 | break; |
1104 | case RM_CONTENT_OBJECT: { |
1105 | retVal = rm_parseri_unpack_content_hdr(pInt); |
1106 | if (retVal != HXR_OK) { |
1107 | /* Call back to the error interface */ |
1108 | rm_parseri_error(pInt, retVal, |
1109 | "Failed to parse content header - possibly a corrupt file."); |
1110 | } |
1111 | } |
1112 | break; |
1113 | case RM_DATA_OBJECT: { |
1114 | bDone = TRUE; |
1115 | } |
1116 | break; |
1117 | } |
1118 | } |
1119 | } |
1120 | if (retVal == HXR_OK) { |
1121 | /* Parse all the logical stream headers */ |
1122 | retVal = rm_parseri_unpack_all_logical_stream_hdrs(pInt); |
1123 | if (retVal == HXR_OK) { |
1124 | /* |
1125 | * Currently we only support single-rate files and |
1126 | * SureStream files who have a backward-compatible |
1127 | * single-rate section. So know we must determine |
1128 | * if we can play this file. |
1129 | */ |
1130 | retVal = rm_parseri_setup_interleaved_streams(pInt); |
1131 | if (retVal == HXR_OK) { |
1132 | pInt->ulInterleavedStreamsFlag = 1; |
1133 | /* Create some structures to hold stream info */ |
1134 | retVal = rm_parseri_create_stream_structures(pInt); |
1135 | if (retVal == HXR_OK) { |
1136 | /* |
1137 | * We will examine the first few packets |
1138 | * of each stream to determine if there is |
1139 | * a packet time offset. |
1140 | */ |
1141 | pInt->pDataHdr = rm_parseri_malloc(pInt, sizeof(struct rm_data_hdr)); |
1142 | if (pInt->pDataHdr) { |
1143 | retVal = rm_parseri_examine_initial_packets(pInt, 0); |
1144 | if (retVal == HXR_OK) { |
1145 | /* Create the stream headers */ |
1146 | retVal = rm_parseri_create_all_stream_headers(pInt); |
1147 | } |
1148 | } else { |
1149 | retVal = HXR_OUTOFMEMORY; |
1150 | } |
1151 | } |
1152 | } else { |
1153 | pInt->ulInterleavedStreamsFlag = 0; |
1154 | retVal = rm_parseri_setup_multirate_streams(pInt); |
1155 | if (retVal == HXR_OK) { |
1156 | /* Create some structures to hold stream info */ |
1157 | retVal = rm_parseri_create_stream_structures(pInt); |
1158 | if (retVal == HXR_OK) { |
1159 | /* |
1160 | * We will examine the first few packets |
1161 | * of each stream to determine if there is |
1162 | * a packet time offset. |
1163 | */ |
1164 | pInt->pDataHdr = rm_parseri_malloc(pInt, pInt->ulNumStreams * sizeof(struct rm_data_hdr)); |
1165 | if (pInt->pDataHdr) { |
1166 | UINT32 j = 0; |
1167 | for (j = 0; j < pInt->ulNumStreams; j++) { |
1168 | retVal = rm_parseri_examine_initial_packets(pInt, j); |
1169 | if (retVal != HXR_OK) { |
1170 | break; |
1171 | } |
1172 | } |
1173 | if (retVal == HXR_OK) { |
1174 | /* Create the stream headers */ |
1175 | retVal = rm_parseri_create_all_stream_headers(pInt); |
1176 | } |
1177 | } else { |
1178 | retVal = HXR_OUTOFMEMORY; |
1179 | } |
1180 | } else { |
1181 | /* |
1182 | * This is a surestream file which has not backwards-compatible |
1183 | * streams, which we do not support. |
1184 | */ |
1185 | retVal = HXR_NOT_SUPPORTED; |
1186 | /* Call back to the error interface */ |
1187 | rm_parseri_error(pInt, retVal, |
1188 | "Unsupported file (SureStream file with no " |
1189 | "compatible streams)"); |
1190 | } |
1191 | } else { |
1192 | retVal = HXR_NOT_SUPPORTED; |
1193 | /* Call back to the error interface */ |
1194 | rm_parseri_error(pInt, retVal, |
1195 | "Unsupported file (SureStream file with no " |
1196 | "compatible streams)"); |
1197 | } |
1198 | } |
1199 | } |
1200 | } |
1201 | } else { |
1202 | /* |
1203 | * This is a later version than we support */ |
1204 | retVal = HXR_NOT_SUPPORTED; |
1205 | /* Call back to the error interface */ |
1206 | rm_parseri_error(pInt, retVal, "Unsupported file header version."); |
1207 | } |
1208 | } |
1209 | } else { |
1210 | /* |
1211 | * The first four bytes of the file were |
1212 | * not what we expected. This is likely not |
1213 | * an .rm file. |
1214 | * XXXMEH: is there a better error code for this? |
1215 | */ |
1216 | retVal = HXR_NOT_SUPPORTED; |
1217 | /* Call back to the error interface */ |
1218 | rm_parseri_error(pInt, retVal, |
1219 | "First four bytes are are not \".RMF\" - this is not an .rm file"); |
1220 | } |
1221 | } |
1222 | } |
1223 | |
1224 | return retVal; |
1225 | } |
1226 | |
1227 | UINT32 rm_parseri_get_num_file_properties(rm_parser_internal* pInt) |
1228 | { |
1229 | UINT32 ulRet = 0; |
1230 | |
1231 | if (pInt) { |
1232 | /* |
1233 | * We always put the "StreamCount" and "Flags" properties. |
1234 | */ |
1235 | ulRet += 2; |
1236 | /* If we have a real datatype, then we will add "IsRealDataType" */ |
1237 | if (rm_parseri_has_real_data_type(pInt)) { |
1238 | ulRet++; |
1239 | } |
1240 | /* |
1241 | * If we have a logical-fileinfo header, we will put in |
1242 | * all the properties in it. |
1243 | */ |
1244 | if (pInt->pLogicalFileInfo) { |
1245 | ulRet += pInt->pLogicalFileInfo->num_props; |
1246 | } |
1247 | /* Add "Title", "Author", "Copyright" if present */ |
1248 | if (pInt->contHdr.title) { |
1249 | ulRet++; |
1250 | } |
1251 | if (pInt->contHdr.author) { |
1252 | ulRet++; |
1253 | } |
1254 | if (pInt->contHdr.copyright) { |
1255 | ulRet++; |
1256 | } |
1257 | } |
1258 | |
1259 | return ulRet; |
1260 | } |
1261 | |
1262 | HX_RESULT rm_parseri_get_file_properties(rm_parser_internal* pInt, |
1263 | rm_property* pProp, UINT32 ulNumProp) |
1264 | { |
1265 | HX_RESULT retVal = HXR_FAIL; |
1266 | |
1267 | if (pInt && pProp && ulNumProp) { |
1268 | /* Init the counter */ |
1269 | UINT32 ulIndex = 0; |
1270 | /* "StreamCount" property */ |
1271 | retVal = rm_parseri_set_rm_property(pInt, &pProp[ulIndex++], "StreamCount", |
1272 | RM_PROPERTY_TYPE_UINT32, |
1273 | (void*) pInt->ulNumStreams, 0); |
1274 | |
1275 | if (retVal == HXR_OK) { |
1276 | retVal = rm_parseri_set_rm_property(pInt, &pProp[ulIndex++], "Flags", |
1277 | RM_PROPERTY_TYPE_UINT32, |
1278 | (void*) pInt->propHdr.flags, 0); |
1279 | } |
1280 | if (retVal == HXR_OK && |
1281 | rm_parseri_has_real_data_type(pInt)) { |
1282 | retVal = rm_parseri_set_rm_property(pInt, &pProp[ulIndex++], "IsRealDataType", |
1283 | RM_PROPERTY_TYPE_UINT32, |
1284 | (void*) 1, 0); |
1285 | } |
1286 | if (retVal == HXR_OK && pInt->contHdr.title) { |
1287 | retVal = rm_parseri_set_rm_property(pInt, &pProp[ulIndex++], "Title", |
1288 | RM_PROPERTY_TYPE_BUFFER, |
1289 | (void*) pInt->contHdr.title, |
1290 | strlen(pInt->contHdr.title) + 1); |
1291 | } |
1292 | if (retVal == HXR_OK && pInt->contHdr.author) { |
1293 | retVal = rm_parseri_set_rm_property(pInt, &pProp[ulIndex++], "Author", |
1294 | RM_PROPERTY_TYPE_BUFFER, |
1295 | (void*) pInt->contHdr.author, |
1296 | strlen(pInt->contHdr.author) + 1); |
1297 | } |
1298 | if (retVal == HXR_OK && pInt->contHdr.copyright) { |
1299 | retVal = rm_parseri_set_rm_property(pInt, &pProp[ulIndex++], "Copyright", |
1300 | RM_PROPERTY_TYPE_BUFFER, |
1301 | (void*) pInt->contHdr.copyright, |
1302 | strlen(pInt->contHdr.copyright) + 1); |
1303 | } |
1304 | if (pInt->pLogicalFileInfo) { |
1305 | UINT32 i = 0; |
1306 | for (i = 0; i < (UINT32) pInt->pLogicalFileInfo->num_props && retVal == HXR_OK; i++) { |
1307 | struct rm_name_value_map* pMap = &pInt->pLogicalFileInfo->props[i]; |
1308 | UINT32 ulLength = pMap->value_sz; |
1309 | if (pMap->type != RM_PROPERTY_TYPE_BUFFER) { |
1310 | ulLength = 0; |
1311 | } |
1312 | retVal = rm_parseri_set_rm_property(pInt, &pProp[ulIndex++], |
1313 | (const char*) pMap->name, |
1314 | pMap->type, pMap->value, ulLength); |
1315 | } |
1316 | } |
1317 | } |
1318 | |
1319 | return retVal; |
1320 | } |
1321 | |
1322 | HXBOOL rm_parseri_has_real_data_type(rm_parser_internal* pInt) |
1323 | { |
1324 | HXBOOL bRet = FALSE; |
1325 | |
1326 | if (pInt) { |
1327 | bRet = pInt->bIsRealDataType; |
1328 | } |
1329 | |
1330 | return bRet; |
1331 | } |
1332 | |
1333 | HX_RESULT rm_parseri_set_rm_property(rm_parser_internal* pInt, rm_property* pProp, |
1334 | const char* pszName, UINT32 ulType, |
1335 | void* pValue, UINT32 ulValueLen) |
1336 | { |
1337 | HX_RESULT retVal = HXR_FAIL; |
1338 | |
1339 | if (pInt && pProp && pszName) { |
1340 | /* Cleanup the existing property */ |
1341 | rm_parseri_cleanup_rm_property(pInt, pProp); |
1342 | /* Allocate space for the name */ |
1343 | pProp->pName = (char*) rm_parseri_malloc(pInt, strlen(pszName) + 1); |
1344 | if (pProp->pName) { |
1345 | /* Copy the string */ |
1346 | strcpy(pProp->pName, pszName); |
1347 | /* Copy the type */ |
1348 | pProp->ulType = ulType; |
1349 | /* What type is this property? */ |
1350 | switch (ulType) { |
1351 | case RM_PROPERTY_TYPE_UINT32: { |
1352 | pProp->pValue = pValue; |
1353 | pProp->ulValueLen = 0; |
1354 | retVal = HXR_OK; |
1355 | } |
1356 | break; |
1357 | case RM_PROPERTY_TYPE_BUFFER: { |
1358 | pProp->pValue = (BYTE*) rm_parseri_malloc(pInt, ulValueLen); |
1359 | if (pProp->pValue) { |
1360 | /* Copy the string */ |
1361 | memcpy(pProp->pValue, pValue, ulValueLen); |
1362 | /* Assign the length */ |
1363 | pProp->ulValueLen = ulValueLen; |
1364 | /* Clear the return value */ |
1365 | retVal = HXR_OK; |
1366 | } |
1367 | } |
1368 | break; |
1369 | case RM_PROPERTY_TYPE_CSTRING: { |
1370 | const char* pszValue = (const char*) pValue; |
1371 | UINT32 ulLen = (UINT32) strlen(pszValue) + 1; |
1372 | pProp->pValue = (BYTE*) rm_parseri_malloc(pInt, ulLen); |
1373 | if (pProp->pValue) { |
1374 | /* Copy the string */ |
1375 | strcpy((char*) pProp->pValue, pszValue); |
1376 | /* Assign the length */ |
1377 | pProp->ulValueLen = ulLen; |
1378 | /* Clear the return value */ |
1379 | retVal = HXR_OK; |
1380 | } |
1381 | } |
1382 | break; |
1383 | } |
1384 | } |
1385 | } |
1386 | |
1387 | return retVal; |
1388 | } |
1389 | |
1390 | void rm_parseri_cleanup_rm_property(rm_parser_internal* pInt, rm_property* pProp) |
1391 | { |
1392 | if (pInt && pProp) { |
1393 | /* Free the name string */ |
1394 | if (pProp->pName) { |
1395 | rm_parseri_free(pInt, pProp->pName); |
1396 | pProp->pName = HXNULL; |
1397 | } |
1398 | /* |
1399 | * If this is a RM_PROPERTY_TYPE_BUFFER or RM_PROPERTY_TYPE_CSTRING |
1400 | * property, then the pValue is an allocated buffer. If this |
1401 | * is an RM_PROPERTY_TYPE_UINT32 property, then pValue doesn't |
1402 | * have any buffer associated with it. |
1403 | */ |
1404 | if (pProp->pValue && pProp->ulType != RM_PROPERTY_TYPE_UINT32) { |
1405 | rm_parseri_free(pInt, pProp->pValue); |
1406 | pProp->pValue = HXNULL; |
1407 | } |
1408 | } |
1409 | } |
1410 | |
1411 | void rm_parseri_cleanup_stream_num_map(rm_parser_internal* pInt) |
1412 | { |
1413 | if (pInt && pInt->pulStreamNumMap) { |
1414 | rm_parseri_free(pInt, pInt->pulStreamNumMap); |
1415 | pInt->pulStreamNumMap = HXNULL; |
1416 | pInt->ulStreamNumMapSize = 0; |
1417 | } |
1418 | } |
1419 | |
1420 | void rm_parseri_cleanup_stream_info(rm_parser_internal* pInt, struct rm_stream_info* pInfo) |
1421 | { |
1422 | if (pInt) { |
1423 | /* Free the index entry array */ |
1424 | if (pInfo->seekTable.pEntry) { |
1425 | rm_parseri_free(pInt, pInfo->seekTable.pEntry); |
1426 | pInfo->seekTable.pEntry = HXNULL; |
1427 | } |
1428 | } |
1429 | } |
1430 | |
1431 | void rm_parseri_cleanup_stream_info_array(rm_parser_internal* pInt) |
1432 | { |
1433 | if (pInt && pInt->pStreamInfo) { |
1434 | /* Clean up each individual stream info */ |
1435 | UINT32 i = 0; |
1436 | for (i = 0; i < pInt->ulNumStreams; i++) { |
1437 | rm_parseri_cleanup_stream_info(pInt, &pInt->pStreamInfo[i]); |
1438 | } |
1439 | /* Clean up the array */ |
1440 | rm_parseri_free(pInt, pInt->pStreamInfo); |
1441 | pInt->pStreamInfo = HXNULL; |
1442 | } |
1443 | } |
1444 | |
1445 | HX_RESULT rm_parseri_create_stream_structures(rm_parser_internal* pInt) |
1446 | { |
1447 | HX_RESULT retVal = HXR_FAIL; |
1448 | |
1449 | if (pInt && pInt->ulNumStreams) { |
1450 | /* |
1451 | * Compute the max stream number and the |
1452 | * max duration across all streams. |
1453 | */ |
1454 | UINT32 i = 0; |
1455 | UINT32 ulSize = 0; |
1456 | UINT32 ulMaxStreamNum = pInt->pMediaPropsHdr[0].stream_num; |
1457 | UINT32 ulMaxDuration = pInt->pMediaPropsHdr[0].duration; |
1458 | UINT32 ulIndexMaxEntries = RM_INDEX_MAX_ENTRIES; |
1459 | UINT32 ulIndexTimeGranularity = ulMaxDuration / ulIndexMaxEntries; |
1460 | for (i = 1; i < pInt->ulNumStreams; i++) { |
1461 | if (pInt->pMediaPropsHdr[i].stream_num > ulMaxStreamNum) { |
1462 | ulMaxStreamNum = pInt->pMediaPropsHdr[i].stream_num; |
1463 | } |
1464 | if (pInt->pMediaPropsHdr[i].duration > ulMaxDuration) { |
1465 | ulMaxDuration = pInt->pMediaPropsHdr[i].duration; |
1466 | } |
1467 | } |
1468 | /* Assign the max duration */ |
1469 | pInt->ulMaxDuration = ulMaxDuration; |
1470 | /* Free any existing stream number map */ |
1471 | rm_parseri_cleanup_stream_num_map(pInt); |
1472 | /* Allocate the stream number map */ |
1473 | pInt->ulStreamNumMapSize = ulMaxStreamNum + 1; |
1474 | ulSize = pInt->ulStreamNumMapSize * sizeof(UINT32); |
1475 | pInt->pulStreamNumMap = (UINT32*) rm_parseri_malloc(pInt, ulSize); |
1476 | if (pInt->pulStreamNumMap) { |
1477 | /* Initialize all the stream numbers in the map */ |
1478 | for (i = 0; i < pInt->ulStreamNumMapSize; i++) { |
1479 | pInt->pulStreamNumMap[i] = RM_NO_STREAM_SET; |
1480 | } |
1481 | /* |
1482 | * The stream number maps maps stream number to |
1483 | * the index in the pMediaPropsHdr array. |
1484 | */ |
1485 | for (i = 0; i < pInt->ulNumStreams; i++) { |
1486 | pInt->pulStreamNumMap[pInt->pMediaPropsHdr[i].stream_num] = i; |
1487 | } |
1488 | /* Clean up any existing stream info array */ |
1489 | rm_parseri_cleanup_stream_info_array(pInt); |
1490 | /* Allocate a stream info array */ |
1491 | ulSize = pInt->ulNumStreams * sizeof(struct rm_stream_info); |
1492 | pInt->pStreamInfo = (struct rm_stream_info*) rm_parseri_malloc(pInt, ulSize); |
1493 | if (pInt->pStreamInfo) { |
1494 | /* Zero out the array */ |
1495 | memset(pInt->pStreamInfo, 0, ulSize); |
1496 | /* Clear the return value */ |
1497 | retVal = HXR_OK; |
1498 | /* Compute the index table parameters */ |
1499 | if (ulIndexTimeGranularity > RM_INDEX_MAX_TIME_GRANULARITY) { |
1500 | ulIndexTimeGranularity = RM_INDEX_MAX_TIME_GRANULARITY; |
1501 | ulIndexMaxEntries = ulMaxDuration / ulIndexTimeGranularity; |
1502 | if (ulIndexMaxEntries > RM_INDEX_MAX_ENTRIES) { |
1503 | ulIndexMaxEntries = RM_INDEX_MAX_ENTRIES; |
1504 | } |
1505 | } else if (ulIndexTimeGranularity < RM_INDEX_MIN_TIME_GRANULARITY) { |
1506 | ulIndexTimeGranularity = RM_INDEX_MIN_TIME_GRANULARITY; |
1507 | ulIndexMaxEntries = ulMaxDuration / ulIndexTimeGranularity; |
1508 | if (ulIndexMaxEntries < RM_INDEX_MIN_ENTRIES) { |
1509 | ulIndexMaxEntries = RM_INDEX_MIN_ENTRIES; |
1510 | } |
1511 | } |
1512 | ulSize = ulIndexMaxEntries * sizeof(struct rm_seek_table_entry); |
1513 | /* Initialize the stream info */ |
1514 | for (i = 0; i < pInt->ulNumStreams && retVal == HXR_OK; i++) { |
1515 | /* Initialize the type flag */ |
1516 | if (pInt->pMediaPropsHdr[i].mime_type) { |
1517 | const char* pszStr = (const char*) pInt->pMediaPropsHdr[i].mime_type; |
1518 | if (rm_stream_is_realaudio_mimetype(pszStr)) { |
1519 | pInt->pStreamInfo[i].bIsRealAudio = TRUE; |
1520 | pInt->bIsRealDataType = TRUE; |
1521 | } else if (rm_stream_is_realvideo_mimetype(pszStr)) { |
1522 | pInt->pStreamInfo[i].bIsRealVideo = TRUE; |
1523 | pInt->bIsRealDataType = TRUE; |
1524 | } else if (rm_stream_is_realevent_mimetype(pszStr)) { |
1525 | pInt->pStreamInfo[i].bIsRealEvent = TRUE; |
1526 | pInt->bIsRealDataType = TRUE; |
1527 | } |
1528 | } |
1529 | /* Initialize the index table */ |
1530 | pInt->pStreamInfo[i].seekTable.pEntry = |
1531 | (struct rm_seek_table_entry*) rm_parseri_malloc(pInt, ulSize); |
1532 | if (pInt->pStreamInfo[i].seekTable.pEntry) { |
1533 | /* Zero out the memory */ |
1534 | memset(pInt->pStreamInfo[i].seekTable.pEntry, 0, ulSize); |
1535 | /* Init the parameters */ |
1536 | pInt->pStreamInfo[i].seekTable.ulMaxEntries = ulIndexMaxEntries; |
1537 | pInt->pStreamInfo[i].seekTable.ulTimeGranularity = ulIndexTimeGranularity; |
1538 | pInt->pStreamInfo[i].seekTable.ulNumEntries = 0; |
1539 | pInt->pStreamInfo[i].seekTable.ulLastTime = 0; |
1540 | pInt->pStreamInfo[i].seekTable.ulRangeTime = 0; |
1541 | } else { |
1542 | retVal = HXR_OUTOFMEMORY; |
1543 | } |
1544 | } |
1545 | } |
1546 | } |
1547 | } |
1548 | |
1549 | return retVal; |
1550 | } |
1551 | |
1552 | HX_RESULT rm_parseri_examine_initial_packets(rm_parser_internal* pInt, UINT32 ulStreamNum) |
1553 | { |
1554 | HX_RESULT retVal = HXR_FAIL; |
1555 | |
1556 | if (pInt) { |
1557 | struct rm_pkt_hdr hdr; |
1558 | UINT32 ulID = 0; |
1559 | UINT32 i = 0; |
1560 | UINT32 j = 0; |
1561 | /* Seek to the data offset mentioned in the properties header */ |
1562 | rm_parseri_file_seek(pInt, pInt->pMediaPropsHdr[ulStreamNum].start_offset, HX_SEEK_ORIGIN_SET); |
1563 | /* |
1564 | * Read the next header into the read buffer, |
1565 | * which should be a data chunk |
1566 | */ |
1567 | retVal = rm_parseri_read_next_header(pInt, &ulID); |
1568 | if (retVal == HXR_OK) { |
1569 | /* Make sure it's a data chunk */ |
1570 | if (ulID == RM_DATA_OBJECT) { |
1571 | /* Parse the data chunk header */ |
1572 | retVal = rm_parseri_unpack_data_hdr(pInt, ulStreamNum); |
1573 | if (retVal == HXR_OK) { |
1574 | /* Initialize the minimum first packet timestamp */ |
1575 | pInt->ulMinFirstPacketTime = 0xFFFFFFFF; |
1576 | /* |
1577 | * Now we will look at the first few packet headers |
1578 | * until either we have seen at least one packet |
1579 | * of each stream or we have verified that the |
1580 | * minimum timestamp across all streams is 0. |
1581 | * We will loop as though we will look at all |
1582 | * packets, but we will break out long before that. |
1583 | */ |
1584 | for (i = 0; i < pInt->pDataHdr[ulStreamNum].num_pkts && retVal == HXR_OK; i++) { |
1585 | retVal = rm_parseri_read_next_packet_header(pInt, &hdr); |
1586 | if (retVal == HXR_OK) { |
1587 | /* Translate the stream number */ |
1588 | UINT32 ulStreamNum = rm_parseri_translate_stream_number(pInt, hdr.stream_num); |
1589 | if (ulStreamNum != RM_NO_STREAM_SET) { |
1590 | /* Save the first timestamp of each stream */ |
1591 | if (!pInt->pStreamInfo[ulStreamNum].bSeenFirstPacketTimeStamp) { |
1592 | pInt->pStreamInfo[ulStreamNum].ulLastTimeStamp = hdr.timestamp; |
1593 | pInt->pStreamInfo[ulStreamNum].bSeenFirstPacketTimeStamp = TRUE; |
1594 | /* Update the min first timestamp */ |
1595 | if (hdr.timestamp < pInt->ulMinFirstPacketTime) { |
1596 | pInt->ulMinFirstPacketTime = hdr.timestamp; |
1597 | } |
1598 | } |
1599 | /* Check if we've seen the first timestamp of all streams */ |
1600 | for (j = 0; j < pInt->ulNumStreams; j++) { |
1601 | if (!pInt->pStreamInfo[ulStreamNum].bSeenFirstPacketTimeStamp) { |
1602 | break; |
1603 | } |
1604 | } |
1605 | /* |
1606 | * Stop if we've seen a packet from each stream |
1607 | * or if we've already seen a timestamp of 0. |
1608 | */ |
1609 | if (j == pInt->ulNumStreams || pInt->ulMinFirstPacketTime == 0) { |
1610 | /* Re-init the last timestamp for each stream */ |
1611 | for (j = 0; j < pInt->ulNumStreams; j++) { |
1612 | pInt->pStreamInfo[j].ulLastTimeStamp = 0xFFFFFFFF; |
1613 | pInt->pStreamInfo[j].ulLastRule = 0; |
1614 | } |
1615 | /* Seek back to right after the data chunk header */ |
1616 | rm_parseri_file_seek(pInt, |
1617 | pInt->pMediaPropsHdr[ulStreamNum].start_offset + |
1618 | RM_PARSER_DATA_CHUNK_HEADER_SIZE, |
1619 | HX_SEEK_ORIGIN_SET); |
1620 | /* Break out of the packet loop */ |
1621 | break; |
1622 | } else { |
1623 | /* |
1624 | * We need to keep reading packets, so |
1625 | * seek past the data of this packet. |
1626 | */ |
1627 | rm_parseri_file_seek(pInt, |
1628 | hdr.length - hdr.header_len, |
1629 | HX_SEEK_ORIGIN_CUR); |
1630 | } |
1631 | } else { |
1632 | retVal = HXR_INVALID_FILE; |
1633 | } |
1634 | } |
1635 | } |
1636 | } |
1637 | } else { |
1638 | retVal = HXR_INVALID_FILE; |
1639 | } |
1640 | } |
1641 | } |
1642 | |
1643 | return retVal; |
1644 | } |
1645 | |
1646 | HX_RESULT rm_parseri_unpack_data_hdr(rm_parser_internal* pInt, UINT32 DataNum) |
1647 | { |
1648 | HX_RESULT retVal = HXR_FAIL; |
1649 | |
1650 | if (pInt) { |
1651 | /* Assign temporary variables */ |
1652 | BYTE* pBuf = pInt->pReadBuffer; |
1653 | UINT32 ulLen = pInt->ulNumBytesRead; |
1654 | if (ulLen >= RM_PARSER_DATA_CHUNK_HEADER_SIZE) { |
1655 | /* Unpack the rm_data_hdr */ |
1656 | pInt->pDataHdr[DataNum].id = rm_unpack32(&pBuf, &ulLen); |
1657 | pInt->pDataHdr[DataNum].size = rm_unpack32(&pBuf, &ulLen); |
1658 | pInt->pDataHdr[DataNum].version = rm_unpack16(&pBuf, &ulLen); |
1659 | pInt->pDataHdr[DataNum].num_pkts = rm_unpack32(&pBuf, &ulLen); |
1660 | pInt->pDataHdr[DataNum].next_data_hdr = rm_unpack32(&pBuf, &ulLen); |
1661 | /* Clear the return value */ |
1662 | retVal = HXR_OK; |
1663 | } |
1664 | } |
1665 | |
1666 | return retVal; |
1667 | } |
1668 | |
1669 | HX_RESULT rm_parseri_unpack_pkt_hdr(rm_parser_internal* pInt, |
1670 | struct rm_pkt_hdr* pPktHdr) |
1671 | { |
1672 | HX_RESULT retVal = HXR_FAIL; |
1673 | |
1674 | if (pInt) { |
1675 | /* Assign temporary variables */ |
1676 | BYTE* pBuf = pInt->pReadBuffer; |
1677 | UINT32 ulLen = pInt->ulNumBytesRead; |
1678 | if (ulLen >= RM_PARSER_PACKET_HEADER_SIZE) { |
1679 | /* Unpack the rm_pkt_hdr */ |
1680 | pPktHdr->version = rm_unpack16(&pBuf, &ulLen); |
1681 | pPktHdr->length = rm_unpack16(&pBuf, &ulLen); |
1682 | pPktHdr->stream_num = rm_unpack16(&pBuf, &ulLen); |
1683 | pPktHdr->timestamp = rm_unpack32(&pBuf, &ulLen); |
1684 | pPktHdr->flags = rm_unpack16(&pBuf, &ulLen); |
1685 | if (pPktHdr->version == 1) { |
1686 | rm_parseri_file_read(pInt, 1, 0); |
1687 | pPktHdr->header_len = 13; |
1688 | if (pPktHdr->flags == 0) { |
1689 | pPktHdr->flags = 2; |
1690 | } |
1691 | } else { |
1692 | pPktHdr->header_len = 12; |
1693 | } |
1694 | /* Clear the return value */ |
1695 | retVal = HXR_OK; |
1696 | } |
1697 | } |
1698 | |
1699 | return retVal; |
1700 | } |
1701 | |
1702 | HX_RESULT rm_parseri_unpack_index_hdr(rm_parser_internal* pInt, |
1703 | struct rm_index_hdr* hdr) |
1704 | { |
1705 | HX_RESULT retVal = HXR_FAIL; |
1706 | |
1707 | if (pInt && hdr) { |
1708 | /* Assign temporary variables */ |
1709 | BYTE* pBuf = pInt->pReadBuffer; |
1710 | UINT32 ulLen = pInt->ulNumBytesRead; |
1711 | if (ulLen >= RM_PARSER_INDEX_HEADER_SIZE) { |
1712 | /* Unpack the rm_index_hdr */ |
1713 | hdr->id = rm_unpack32(&pBuf, &ulLen); |
1714 | hdr->size = rm_unpack32(&pBuf, &ulLen); |
1715 | hdr->version = rm_unpack16(&pBuf, &ulLen); |
1716 | hdr->num_recs = rm_unpack32(&pBuf, &ulLen); |
1717 | hdr->stream_num = rm_unpack16(&pBuf, &ulLen); |
1718 | hdr->next_index_hdr = rm_unpack32(&pBuf, &ulLen); |
1719 | /* Clear the return value */ |
1720 | retVal = HXR_OK; |
1721 | } |
1722 | } |
1723 | |
1724 | return retVal; |
1725 | } |
1726 | |
1727 | HX_RESULT rm_parseri_unpack_index_rec(rm_parser_internal* pInt, |
1728 | struct rm_index_rec* rec) |
1729 | { |
1730 | HX_RESULT retVal = HXR_FAIL; |
1731 | |
1732 | if (pInt && rec) { |
1733 | /* Assign temporary variables */ |
1734 | BYTE* pBuf = pInt->pReadBuffer; |
1735 | UINT32 ulLen = pInt->ulNumBytesRead; |
1736 | if (ulLen >= RM_PARSER_INDEX_RECORD_SIZE) { |
1737 | /* Unpack the rm_index_rec */ |
1738 | rec->version = rm_unpack16(&pBuf, &ulLen); |
1739 | rec->timestamp = rm_unpack32(&pBuf, &ulLen); |
1740 | rec->offset = rm_unpack32(&pBuf, &ulLen); |
1741 | rec->num_pkts = rm_unpack32(&pBuf, &ulLen); |
1742 | /* Clear the return value */ |
1743 | retVal = HXR_OK; |
1744 | } |
1745 | } |
1746 | |
1747 | return retVal; |
1748 | } |
1749 | |
1750 | HX_RESULT rm_parseri_read_next_index_rec(rm_parser_internal* pInt, |
1751 | struct rm_index_rec* rec) |
1752 | { |
1753 | HX_RESULT retVal = HXR_FAIL; |
1754 | |
1755 | if (pInt && rec) { |
1756 | UINT32 ulNumBytesRead = 0; |
1757 | /* Change the error return */ |
1758 | retVal = HXR_READ_ERROR; |
1759 | /* Read the packet header into the read buffer */ |
1760 | ulNumBytesRead = rm_parseri_file_read(pInt, RM_PARSER_INDEX_RECORD_SIZE, 0); |
1761 | if (ulNumBytesRead == RM_PARSER_INDEX_RECORD_SIZE) { |
1762 | /* Unpack the packet header */ |
1763 | retVal = rm_parseri_unpack_index_rec(pInt, rec); |
1764 | } |
1765 | } |
1766 | |
1767 | return retVal; |
1768 | } |
1769 | |
1770 | UINT32 rm_parseri_translate_stream_number(rm_parser_internal* pInt, UINT32 ulNum) |
1771 | { |
1772 | UINT32 ulRet = RM_NO_STREAM_SET; |
1773 | |
1774 | if (pInt && pInt->pulStreamNumMap && ulNum < pInt->ulStreamNumMapSize) { |
1775 | ulRet = pInt->pulStreamNumMap[ulNum]; |
1776 | } |
1777 | |
1778 | return ulRet; |
1779 | } |
1780 | |
1781 | UINT32 rm_parseri_get_stream_number(rm_parser_internal* pInt, UINT32 ulNum) |
1782 | { |
1783 | UINT32 ulRet = 0; |
1784 | |
1785 | if (pInt && pInt->pulStreamNumMap) { |
1786 | for (ulRet = 0; ulRet < pInt->ulStreamNumMapSize; ulRet++) { |
1787 | if (pInt->pulStreamNumMap[ulRet] == ulNum) { |
1788 | return ulRet; |
1789 | } |
1790 | } |
1791 | } |
1792 | ulRet = RM_NO_STREAM_SET; |
1793 | return ulRet; |
1794 | } |
1795 | |
1796 | HX_RESULT rm_parseri_create_all_stream_headers(rm_parser_internal* pInt) |
1797 | { |
1798 | HX_RESULT retVal = HXR_FAIL; |
1799 | |
1800 | if (pInt && pInt->ulNumStreams) { |
1801 | UINT32 i = 0; |
1802 | UINT32 ulSize = 0; |
1803 | /* Clean up any existing stream headers */ |
1804 | rm_parseri_cleanup_all_stream_headers(pInt); |
1805 | /* Allocate memory for the stream header array */ |
1806 | ulSize = pInt->ulNumStreams * sizeof(rm_stream_header); |
1807 | pInt->pStreamHdr = (rm_stream_header*) rm_parseri_malloc(pInt, ulSize); |
1808 | if (pInt->pStreamHdr) { |
1809 | /* NULL out the memory */ |
1810 | memset(pInt->pStreamHdr, 0, ulSize); |
1811 | /* Clear the return value */ |
1812 | retVal = HXR_OK; |
1813 | /* Create all stream headers */ |
1814 | for (i = 0; i < pInt->ulNumStreams && retVal == HXR_OK; i++) { |
1815 | retVal = rm_parseri_create_stream_header(pInt, i, &pInt->pStreamHdr[i]); |
1816 | } |
1817 | } |
1818 | } |
1819 | return retVal; |
1820 | } |
1821 | |
1822 | HX_RESULT rm_parseri_create_stream_header(rm_parser_internal* pInt, UINT32 i, rm_stream_header* hdr) |
1823 | { |
1824 | HX_RESULT retVal = HXR_FAIL; |
1825 | |
1826 | if (pInt && pInt->pMediaPropsHdr && i < pInt->ulNumStreams && hdr) { |
1827 | UINT32 ulNumProps = 0; |
1828 | UINT32 ulSize = 0; |
1829 | /* |
1830 | * Count the number of properties. Passing in |
1831 | * HXNULL and 0 means just count and don't set |
1832 | * the properties |
1833 | */ |
1834 | ulNumProps = rm_parseri_count_set_stream_header_props(pInt, i, hdr, |
1835 | HXNULL, 0); |
1836 | if (ulNumProps) { |
1837 | /* Compute the size of the array */ |
1838 | ulSize = ulNumProps * sizeof(rm_property); |
1839 | /* Allocate the array */ |
1840 | hdr->pProperty = (rm_property*) rm_parseri_malloc(pInt, ulSize); |
1841 | if (hdr->pProperty) { |
1842 | /* NULL out the array */ |
1843 | memset(hdr->pProperty, 0, ulSize); |
1844 | /* Set the number of properties */ |
1845 | hdr->ulNumProperties = ulNumProps; |
1846 | /* Call again, but this time pass in array */ |
1847 | rm_parseri_count_set_stream_header_props(pInt, i, hdr, |
1848 | hdr->pProperty, |
1849 | hdr->ulNumProperties); |
1850 | /* |
1851 | * Now set the properties for which we |
1852 | * have dedicated convenience members. These |
1853 | * are also duplicated in the rm_property array. |
1854 | */ |
1855 | hdr->ulStreamNumber = i; |
1856 | hdr->ulMaxBitRate = pInt->pMediaPropsHdr[i].max_bit_rate; |
1857 | hdr->ulAvgBitRate = pInt->pMediaPropsHdr[i].avg_bit_rate; |
1858 | hdr->ulMaxPacketSize = pInt->pMediaPropsHdr[i].max_pkt_size; |
1859 | hdr->ulAvgPacketSize = pInt->pMediaPropsHdr[i].avg_pkt_size; |
1860 | hdr->ulDuration = pInt->pMediaPropsHdr[i].duration; |
1861 | hdr->ulPreroll = pInt->pMediaPropsHdr[i].preroll; |
1862 | hdr->ulStartTime = pInt->pMediaPropsHdr[i].start_time; |
1863 | hdr->ulStartOffset = pInt->pMediaPropsHdr[i].start_offset; |
1864 | if (pInt->ulInterleavedStreamsFlag) { |
1865 | hdr->ulStreamSize = pInt->pDataHdr->size; |
1866 | } else { |
1867 | hdr->ulStreamSize = pInt->pDataHdr[i].size; |
1868 | } |
1869 | hdr->pMimeType = copy_string(pInt->pUserMem, pInt->fpMalloc, |
1870 | (const char*) pInt->pMediaPropsHdr[i].mime_type); |
1871 | hdr->pStreamName = copy_string(pInt->pUserMem, pInt->fpMalloc, |
1872 | (const char*) pInt->pMediaPropsHdr[i].stream_name); |
1873 | hdr->pOpaqueData = copy_buffer(pInt->pUserMem, pInt->fpMalloc, |
1874 | pInt->pMediaPropsHdr[i].type_spec, |
1875 | pInt->pMediaPropsHdr[i].type_spec_sz); |
1876 | hdr->ulOpaqueDataLen = pInt->pMediaPropsHdr[i].type_spec_sz; |
1877 | /* Clear the return value */ |
1878 | retVal = HXR_OK; |
1879 | } |
1880 | } |
1881 | } |
1882 | return retVal; |
1883 | } |
1884 | |
1885 | void rm_parseri_cleanup_all_stream_headers(rm_parser_internal* pInt) |
1886 | { |
1887 | if (pInt && pInt->pStreamHdr) { |
1888 | /* Free the memory associated with each stream header */ |
1889 | UINT32 i = 0; |
1890 | for (i = 0; i < pInt->ulNumStreams; i++) { |
1891 | rm_parseri_cleanup_stream_header(pInt, &pInt->pStreamHdr[i]); |
1892 | } |
1893 | /* Free the memory for the array */ |
1894 | rm_parseri_free(pInt, pInt->pStreamHdr); |
1895 | /* NULL out the pointer */ |
1896 | pInt->pStreamHdr = HXNULL; |
1897 | } |
1898 | } |
1899 | |
1900 | void rm_parseri_cleanup_stream_header(rm_parser_internal* pInt, rm_stream_header* hdr) |
1901 | { |
1902 | if (pInt && hdr) { |
1903 | /* Free the mime type string */ |
1904 | if (hdr->pMimeType) { |
1905 | rm_parseri_free(pInt, hdr->pMimeType); |
1906 | hdr->pMimeType = HXNULL; |
1907 | } |
1908 | /* Free the stream name string */ |
1909 | if (hdr->pStreamName) { |
1910 | rm_parseri_free(pInt, hdr->pStreamName); |
1911 | hdr->pStreamName = HXNULL; |
1912 | } |
1913 | /* Free the opaque data buffer */ |
1914 | if (hdr->pOpaqueData) { |
1915 | rm_parseri_free(pInt, hdr->pOpaqueData); |
1916 | hdr->pOpaqueData = HXNULL; |
1917 | hdr->ulOpaqueDataLen = 0; |
1918 | } |
1919 | /* Do we have any properties? */ |
1920 | if (hdr->pProperty) { |
1921 | /* Clean up each individual rm_property */ |
1922 | UINT32 i = 0; |
1923 | for (i = 0; i < hdr->ulNumProperties; i++) { |
1924 | rm_parseri_cleanup_rm_property(pInt, &hdr->pProperty[i]); |
1925 | } |
1926 | /* Free the memory for the property array */ |
1927 | rm_parseri_free(pInt, hdr->pProperty); |
1928 | /* Null out the pointer */ |
1929 | hdr->pProperty = HXNULL; |
1930 | hdr->ulNumProperties = 0; |
1931 | } |
1932 | } |
1933 | } |
1934 | |
1935 | void rm_parseri_cleanup_all_data_headers(rm_parser_internal* pInt) |
1936 | { |
1937 | if (pInt && pInt->pDataHdr) { |
1938 | rm_parseri_free(pInt, pInt->pDataHdr); |
1939 | pInt->pDataHdr = HXNULL; |
1940 | } |
1941 | } |
1942 | |
1943 | UINT32 rm_parseri_count_set_stream_header_props(rm_parser_internal* pInt, UINT32 i, |
1944 | rm_stream_header* hdr, |
1945 | rm_property* pProp, UINT32 ulNumProps) |
1946 | { |
1947 | UINT32 ulRet = 0; |
1948 | |
1949 | if (pInt && i < pInt->ulNumStreams && hdr) { |
1950 | /* Initialize some local variables used later */ |
1951 | UINT32 ulDuration = pInt->pMediaPropsHdr[i].duration; |
1952 | UINT32 ulPreroll = pInt->pMediaPropsHdr[i].preroll; |
1953 | UINT32 ulStreamingPreroll = 0; |
1954 | UINT32 ulOldPreroll = 0; |
1955 | UINT32 ulPreDecBufSize = 0; |
1956 | UINT32 ulPreDecBufTime = 0; |
1957 | HXDOUBLE dPreDecBufSize = 0.0; |
1958 | HXBOOL bIsVBR = (pInt->pMediaPropsHdr[i].max_bit_rate != |
1959 | pInt->pMediaPropsHdr[i].avg_bit_rate ? TRUE : FALSE); |
1960 | HXBOOL bHasPreDataProps = FALSE; |
1961 | HXDOUBLE dPreData = 0.0; |
1962 | UINT32 ulPreData = 0; |
1963 | char* pASMRuleBook = HXNULL; |
1964 | BYTE* pBuf = HXNULL; |
1965 | UINT32 ulLen = 0; |
1966 | BYTE ucRuleToFlag[8]; |
1967 | /* Set/count the "StreamNumber" property */ |
1968 | |
1969 | if (pProp) { |
1970 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "StreamNumber", |
1971 | RM_PROPERTY_TYPE_UINT32, (void*) i, 0); |
1972 | } |
1973 | ulRet++; |
1974 | /* Set/count the "MaxBitRate" property */ |
1975 | if (pInt->pMediaPropsHdr[i].max_bit_rate) { |
1976 | if (pProp) { |
1977 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "MaxBitRate", |
1978 | RM_PROPERTY_TYPE_UINT32, |
1979 | (void*) pInt->pMediaPropsHdr[i].max_bit_rate, 0); |
1980 | } |
1981 | ulRet++; |
1982 | } |
1983 | /* Set/count the "AvgBitRate" property */ |
1984 | if (pInt->pMediaPropsHdr[i].avg_bit_rate) { |
1985 | if (pProp) { |
1986 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "AvgBitRate", |
1987 | RM_PROPERTY_TYPE_UINT32, |
1988 | (void*) pInt->pMediaPropsHdr[i].avg_bit_rate, 0); |
1989 | } |
1990 | ulRet++; |
1991 | } |
1992 | /* Set/count the "MaxPacketSize" property */ |
1993 | if (pInt->pMediaPropsHdr[i].max_pkt_size) { |
1994 | if (pProp) { |
1995 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "MaxPacketSize", |
1996 | RM_PROPERTY_TYPE_UINT32, |
1997 | (void*) pInt->pMediaPropsHdr[i].max_pkt_size, 0); |
1998 | } |
1999 | ulRet++; |
2000 | } |
2001 | /* Set/count the "AvgPacketSize" property */ |
2002 | if (pInt->pMediaPropsHdr[i].avg_pkt_size) { |
2003 | if (pProp) { |
2004 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "AvgPacketSize", |
2005 | RM_PROPERTY_TYPE_UINT32, |
2006 | (void*) pInt->pMediaPropsHdr[i].avg_pkt_size, 0); |
2007 | } |
2008 | ulRet++; |
2009 | } |
2010 | /* Set/count the "StartTime" property */ |
2011 | if (pInt->pMediaPropsHdr[i].start_time) { |
2012 | if (pProp) { |
2013 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "StartTime", |
2014 | RM_PROPERTY_TYPE_UINT32, |
2015 | (void*) pInt->pMediaPropsHdr[i].start_time, 0); |
2016 | } |
2017 | ulRet++; |
2018 | } |
2019 | /* Set/count the "MimeType" property */ |
2020 | if (pInt->pMediaPropsHdr[i].mime_type) { |
2021 | if (pProp) { |
2022 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "MimeType", |
2023 | RM_PROPERTY_TYPE_CSTRING, |
2024 | (void*) pInt->pMediaPropsHdr[i].mime_type, 0); |
2025 | } |
2026 | ulRet++; |
2027 | } |
2028 | /* Set/count the "StreamName" property */ |
2029 | if (pInt->pMediaPropsHdr[i].stream_name) { |
2030 | if (pProp) { |
2031 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "StreamName", |
2032 | RM_PROPERTY_TYPE_CSTRING, |
2033 | (void*) pInt->pMediaPropsHdr[i].stream_name, 0); |
2034 | } |
2035 | ulRet++; |
2036 | } |
2037 | /* Set/count the "OpaqueData" property */ |
2038 | if (pInt->pMediaPropsHdr[i].type_spec) { |
2039 | if (pProp) { |
2040 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "OpaqueData", |
2041 | RM_PROPERTY_TYPE_BUFFER, |
2042 | (void*) pInt->pMediaPropsHdr[i].type_spec, |
2043 | pInt->pMediaPropsHdr[i].type_spec_sz); |
2044 | } |
2045 | ulRet++; |
2046 | } |
2047 | /* Set/count the "intrinsicDurationType" property */ |
2048 | if (pInt->pStreamInfo[i].bIsRealAudio || |
2049 | pInt->pStreamInfo[i].bIsRealVideo || |
2050 | pInt->pStreamInfo[i].bIsRealEvent) { |
2051 | if (pProp) { |
2052 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "intrinsicDurationType", |
2053 | RM_PROPERTY_TYPE_CSTRING, |
2054 | (void*) "intrinsicDurationContinuous", 0); |
2055 | } |
2056 | ulRet++; |
2057 | } |
2058 | /* Set/count the "EndTime" property */ |
2059 | if (pInt->pMediaPropsHdr[i].duration > pInt->propHdr.duration) { |
2060 | if (pProp) { |
2061 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "EndTime", |
2062 | RM_PROPERTY_TYPE_UINT32, |
2063 | (void*) pInt->propHdr.duration, 0); |
2064 | } |
2065 | ulRet++; |
2066 | } |
2067 | /* Set/count the "EndOneRuleEndAll" property */ |
2068 | if (pInt->pStreamInfo[i].bIsRealAudio || |
2069 | pInt->pStreamInfo[i].bIsRealVideo) { |
2070 | if (pProp) { |
2071 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "EndOneRuleEndAll", |
2072 | RM_PROPERTY_TYPE_UINT32, (void*) 1, 0); |
2073 | } |
2074 | ulRet++; |
2075 | } |
2076 | /* Set/count the "CanBeStoppedAnyTime" property */ |
2077 | if (pInt->pStreamInfo[i].bIsRealEvent) { |
2078 | if (pProp) { |
2079 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "CanBeStoppedAnyTime", |
2080 | RM_PROPERTY_TYPE_UINT32, (void*) 1, 0); |
2081 | } |
2082 | ulRet++; |
2083 | } |
2084 | /* Do some adjustments to duration */ |
2085 | if (pInt->pStreamInfo[i].bIsRealEvent) { |
2086 | /* |
2087 | * If this is an event stream, then set the stream duration |
2088 | * to the maximum duration across all streams. |
2089 | */ |
2090 | ulDuration = pInt->ulMaxDuration; |
2091 | } |
2092 | /* Subtract off the min first packet time */ |
2093 | if (ulDuration > pInt->ulMinFirstPacketTime) { |
2094 | ulDuration -= pInt->ulMinFirstPacketTime; |
2095 | } |
2096 | /* Set/count the "Duration" property */ |
2097 | if (pProp) { |
2098 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "Duration", |
2099 | RM_PROPERTY_TYPE_UINT32, |
2100 | (void*) ulDuration, 0); |
2101 | } |
2102 | ulRet++; |
2103 | /* Do some adjustments to preroll values */ |
2104 | if (pInt->pStreamInfo[i].bIsRealAudio) { |
2105 | /* Save the preroll */ |
2106 | ulOldPreroll = ulPreroll; |
2107 | /* |
2108 | * RealAudio streams need to have 2 superblocks as the preroll value. |
2109 | * Encoders put one superblock duration as the preroll. |
2110 | */ |
2111 | ulPreroll = (ulPreroll ? ulPreroll * 2 : 6000); |
2112 | } |
2113 | if (pInt->pStreamInfo[i].bIsRealVideo || |
2114 | pInt->pStreamInfo[i].bIsRealAudio) { |
2115 | /* Compute the pre-decode buffer size */ |
2116 | if (pInt->pStreamInfo[i].bIsRealVideo) { |
2117 | /* For VBR stream, the PreDecBufTime is the same as the actual preroll */ |
2118 | if (bIsVBR) { |
2119 | ulPreDecBufTime = ulPreroll; |
2120 | } |
2121 | /* |
2122 | * If actual preroll is less than 1 sec, set preroll |
2123 | * and PreDecBufTime to 1 sec more than ActualPreroll |
2124 | */ |
2125 | if (ulPreroll < 1000) { |
2126 | if (ulOldPreroll == 0) { |
2127 | ulOldPreroll = ulPreroll; |
2128 | } |
2129 | ulPreroll += 1000; |
2130 | if (!bIsVBR) { |
2131 | ulPreDecBufTime = ulPreroll; |
2132 | } |
2133 | } else if (!bIsVBR) { |
2134 | /* |
2135 | * Otherwise for CBR set the PreDecBufTime to |
2136 | * twice the actual preroll |
2137 | */ |
2138 | ulPreDecBufTime = ulPreroll * 2; |
2139 | } |
2140 | /* Now compute pre-decode buffer size, rounding up */ |
2141 | dPreDecBufSize = (((HXDOUBLE) ulPreDecBufTime) * |
2142 | ((HXDOUBLE) pInt->pMediaPropsHdr[i].max_bit_rate) + |
2143 | 7999.0) / 8000.0; |
2144 | ulPreDecBufSize = (UINT32) dPreDecBufSize; |
2145 | } |
2146 | /* |
2147 | * Cap the preroll at 5000 ms. |
2148 | * XXXMEH - this assumes local playback |
2149 | */ |
2150 | if (ulPreroll > 5000) { |
2151 | if (!ulOldPreroll) { |
2152 | ulOldPreroll = ulPreroll; |
2153 | } |
2154 | ulStreamingPreroll = ulPreroll; |
2155 | ulPreroll = 5000; |
2156 | } |
2157 | } |
2158 | /* Set/count the "Preroll" property */ |
2159 | if (pProp) { |
2160 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "Preroll", |
2161 | RM_PROPERTY_TYPE_UINT32, |
2162 | (void*) ulPreroll, 0); |
2163 | } |
2164 | ulRet++; |
2165 | /* Set/count the "ActualPreroll" property */ |
2166 | if (ulOldPreroll) { |
2167 | if (pProp) { |
2168 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "ActualPreroll", |
2169 | RM_PROPERTY_TYPE_UINT32, |
2170 | (void*) ulOldPreroll, 0); |
2171 | } |
2172 | ulRet++; |
2173 | } |
2174 | /* Set/count the "StreamingPreroll" property */ |
2175 | if (ulStreamingPreroll) { |
2176 | if (pProp) { |
2177 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "StreamingPreroll", |
2178 | RM_PROPERTY_TYPE_UINT32, |
2179 | (void*) ulStreamingPreroll, 0); |
2180 | } |
2181 | ulRet++; |
2182 | } |
2183 | /* Set/count the "X-PreDecBufSize" property */ |
2184 | if (ulPreDecBufSize) { |
2185 | if (pProp) { |
2186 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "X-PreDecBufSize", |
2187 | RM_PROPERTY_TYPE_UINT32, |
2188 | (void*) ulPreDecBufSize, 0); |
2189 | } |
2190 | ulRet++; |
2191 | } |
2192 | /* Create the ASM rule book string */ |
2193 | pASMRuleBook = rm_parseri_create_asm_rulebook(pInt, |
2194 | pInt->pStreamInfo[i].bIsRealVideo, |
2195 | pInt->pStreamInfo[i].bIsRealEvent, |
2196 | (pInt->pMediaPropsHdr[i].type_spec_sz ? TRUE : FALSE), |
2197 | pInt->pMediaPropsHdr[i].max_bit_rate, |
2198 | pInt->pMediaPropsHdr[i].avg_bit_rate, |
2199 | &bHasPreDataProps); |
2200 | if (pASMRuleBook) { |
2201 | /* Set/count the "ASMRuleBook" property */ |
2202 | if (pProp) { |
2203 | /* Set it into the property */ |
2204 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "ASMRuleBook", |
2205 | RM_PROPERTY_TYPE_CSTRING, |
2206 | (void*) pASMRuleBook, 0); |
2207 | } |
2208 | ulRet++; |
2209 | } |
2210 | /* Free the string */ |
2211 | free_string(pInt->pUserMem, pInt->fpFree, &pASMRuleBook); |
2212 | /* Set/count the pre-data related properties */ |
2213 | if (bHasPreDataProps) { |
2214 | dPreData = ((HXDOUBLE) ulPreroll) * |
2215 | ((HXDOUBLE) pInt->pMediaPropsHdr[i].max_bit_rate) / |
2216 | 8000.0; |
2217 | ulPreData = (UINT32)(dPreData + 0.5); |
2218 | if (ulPreData) { |
2219 | if (pProp) { |
2220 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "PreData", |
2221 | RM_PROPERTY_TYPE_UINT32, |
2222 | (void*) ulPreData, 0); |
2223 | rm_parseri_set_rm_property(pInt, &pProp[ulRet + 1], "PreDataAtStart", |
2224 | RM_PROPERTY_TYPE_UINT32, (void*) 1, 0); |
2225 | rm_parseri_set_rm_property(pInt, &pProp[ulRet + 2], "PreDataAfterSeek", |
2226 | RM_PROPERTY_TYPE_UINT32, (void*) 1, 0); |
2227 | rm_parseri_set_rm_property(pInt, &pProp[ulRet + 3], "PrerollAfterSeek", |
2228 | RM_PROPERTY_TYPE_UINT32, (void*) 1, 0); |
2229 | } |
2230 | ulRet += 4; |
2231 | } |
2232 | } |
2233 | /* Set/count the "RMFF 1.0 Flags" property */ |
2234 | if (pInt->pStreamInfo[i].bIsRealVideo || |
2235 | pInt->pStreamInfo[i].bIsRealEvent || |
2236 | pInt->pMediaPropsHdr[i].type_spec_sz) { |
2237 | if (pProp) { |
2238 | if (pInt->pStreamInfo[i].bIsRealVideo) { |
2239 | /* |
2240 | * For video streams, we will set 3 rules. Rule 0 |
2241 | * is a keyframe rule, rule 1 is a non-keyframe rule, |
2242 | * and rule 2 is a keyframe (thinning) rule. |
2243 | */ |
2244 | BYTE* pBuf = &ucRuleToFlag[0]; |
2245 | UINT32 ulLen = 8; |
2246 | rm_pack16(3, &pBuf, &ulLen); |
2247 | rm_pack16(HX_KEYFRAME_FLAG, &pBuf, &ulLen); |
2248 | rm_pack16(0, &pBuf, &ulLen); |
2249 | rm_pack16(HX_KEYFRAME_FLAG, &pBuf, &ulLen); |
2250 | /* Set the property */ |
2251 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "RMFF 1.0 Flags", |
2252 | RM_PROPERTY_TYPE_BUFFER, |
2253 | (void*) &ucRuleToFlag[0], 8); |
2254 | } else if (pInt->pStreamInfo[i].bIsRealEvent || |
2255 | pInt->pMediaPropsHdr[i].type_spec_sz) { |
2256 | /* |
2257 | * For non-video streams, we will set 2 rules. Rule 0 |
2258 | * is a keyframe rule, rule 1 is a non-keyframe rule. |
2259 | */ |
2260 | BYTE* pBuf = &ucRuleToFlag[0]; |
2261 | UINT32 ulLen = 8; |
2262 | rm_pack16(2, &pBuf, &ulLen); |
2263 | rm_pack16(HX_KEYFRAME_FLAG, &pBuf, &ulLen); |
2264 | rm_pack16(0, &pBuf, &ulLen); |
2265 | /* Set the property */ |
2266 | rm_parseri_set_rm_property(pInt, &pProp[ulRet], "RMFF 1.0 Flags", |
2267 | RM_PROPERTY_TYPE_BUFFER, |
2268 | (void*) &ucRuleToFlag[0], 6); |
2269 | } |
2270 | } |
2271 | ulRet++; |
2272 | } |
2273 | } |
2274 | return ulRet; |
2275 | } |
2276 | |
2277 | char* rm_parseri_create_asm_rulebook(rm_parser_internal* pInt, HXBOOL bIsRealVideo, |
2278 | HXBOOL bIsRealEvent, HXBOOL bHasOpaqueData, |
2279 | UINT32 ulMaxBitRate, UINT32 ulAvgBitRate, |
2280 | HXBOOL* pbHasPreDataProps) |
2281 | { |
2282 | char* pRet = HXNULL; |
2283 | |
2284 | if (pInt && pbHasPreDataProps) { |
2285 | HXBOOL bIsVBR = (ulMaxBitRate != ulAvgBitRate ? TRUE : FALSE); |
2286 | /* Allocate the output buffer */ |
2287 | pRet = (char*) rm_parseri_malloc(pInt, RM_PARSER_RULE_BOOK_BUFFER_SIZE); |
2288 | if (pRet) { |
2289 | /* Is this a RealVideo stream? */ |
2290 | if (bIsRealVideo) { |
2291 | /* Is this VBR? */ |
2292 | if (bIsVBR) { |
2293 | if (ulMaxBitRate) { |
2294 | /* VBR RealVideo with max_bit_rate != 0 */ |
2295 | strcpy(pRet, g_pszRuleBook[0]);//, 9, ulAvgBitRate, ulMaxBitRate, 5); |
2296 | } else { |
2297 | /* VBR RealVideo with max_bit_rate == 0 */ |
2298 | strcpy(pRet, g_pszRuleBook[1]);//, 9, ulAvgBitRate, 5); |
2299 | } |
2300 | /* Set the PreData flag */ |
2301 | *pbHasPreDataProps = TRUE; |
2302 | } else { |
2303 | /* CBR video */ |
2304 | strcpy(pRet, g_pszRuleBook[5]);//, ulAvgBitRate, ulAvgBitRate, |
2305 | // ulAvgBitRate, ulAvgBitRate); |
2306 | } |
2307 | } else if (bIsRealEvent || bHasOpaqueData) { |
2308 | /* This is most likely an event or audio stream */ |
2309 | if (bIsRealEvent) { |
2310 | /* RealEvent stream */ |
2311 | strcpy(pRet, g_pszRuleBook[6]); |
2312 | } else if (bIsVBR) { |
2313 | /* Most likely an audio stream */ |
2314 | if (ulMaxBitRate) { |
2315 | /* VBR RealAudio with max_bit_rate != 0 */ |
2316 | strcpy(pRet, g_pszRuleBook[0]);//, 5, ulAvgBitRate, ulMaxBitRate, 5); |
2317 | } else { |
2318 | /* VBR RealAudio with max_bit_rate == 0 */ |
2319 | strcpy(pRet, g_pszRuleBook[1]);//, 5, ulAvgBitRate, 5); |
2320 | } |
2321 | /* Set the PreData flag */ |
2322 | *pbHasPreDataProps = TRUE; |
2323 | } else { |
2324 | /* CBR RealAudio */ |
2325 | strcpy(pRet, g_pszRuleBook[7]);//, ulAvgBitRate); |
2326 | } |
2327 | } else { |
2328 | /* Non-RealAudio/RealVideo/RealEvent streams */ |
2329 | if (bIsVBR) { |
2330 | if (ulMaxBitRate) { |
2331 | strcpy(pRet, g_pszRuleBook[2]);//, ulAvgBitRate, ulMaxBitRate); |
2332 | } else if (ulAvgBitRate) { |
2333 | strcpy(pRet, g_pszRuleBook[3]);//, ulAvgBitRate); |
2334 | } else { |
2335 | strcpy(pRet, g_pszRuleBook[4]); |
2336 | } |
2337 | } else { |
2338 | /* CBR Non-RealAudio/RealVideo/RealEvent streams */ |
2339 | strcpy(pRet, g_pszRuleBook[8]);//, ulAvgBitRate); |
2340 | } |
2341 | } |
2342 | } |
2343 | } |
2344 | |
2345 | return pRet; |
2346 | } |
2347 | |
2348 | HX_RESULT rm_parseri_read_next_packet(rm_parser_internal* pInt, rm_packet** ppPacket) |
2349 | { |
2350 | HX_RESULT retVal = HXR_FAIL; |
2351 | |
2352 | if (pInt && ppPacket) { |
2353 | /* Make sure we're still in the range of the data chunk */ |
2354 | if (pInt->ulCurFileOffset < pInt->pMediaPropsHdr[pInt->ulCurrentStream].start_offset + pInt->pDataHdr[pInt->ulCurrentStream].size) { |
2355 | /* More packets to go - read the next one */ |
2356 | struct rm_pkt_hdr hdr; |
2357 | rm_packet* pPacket = HXNULL; |
2358 | UINT32 ulStreamNum = 0; |
2359 | UINT32 ulASMRule = 0; |
2360 | UINT32 ulASMFlags = 0; |
2361 | UINT32 ulLastPacketTime = 0; |
2362 | UINT32 ulLastRule = 0; |
2363 | UINT32 ulBytesRead = 0; |
2364 | UINT32 ulDataSize = 0; |
2365 | UINT32 ulPacketOffset = 0; |
2366 | HXBOOL bSkipPacket = FALSE; |
2367 | do { |
2368 | retVal = rm_parseri_read_next_packet_header(pInt, &hdr); |
2369 | if (retVal == HXR_OK) { |
2370 | /* Assume the worst */ |
2371 | retVal = HXR_FAIL; |
2372 | /* Translate the stream number */ |
2373 | ulStreamNum = rm_parseri_translate_stream_number(pInt, hdr.stream_num); |
2374 | if (ulStreamNum != RM_NO_STREAM_SET) { |
2375 | /* Get the rm_stream_info for this stream */ |
2376 | struct rm_stream_info* pInfo = &pInt->pStreamInfo[ulStreamNum]; |
2377 | if (pInfo) { |
2378 | /* Clear the return value */ |
2379 | retVal = HXR_OK; |
2380 | /* Are we currently looking for keyframes? */ |
2381 | if (pInt->ulKeyframesNeeded) { |
2382 | /* |
2383 | * Is this a keyframe, and do we need a keyframe |
2384 | * for this stream? |
2385 | */ |
2386 | if (!pInfo->bNeedKeyframe || |
2387 | ((hdr.flags & HX_KEYFRAME_FLAG) && |
2388 | (!pInfo->keyFramePacket.bValid || |
2389 | hdr.timestamp >= pInfo->keyFramePacket.ulTimestamp))) { |
2390 | if (pInfo->bNeedKeyframe) { |
2391 | pInfo->bNeedKeyframe = FALSE; |
2392 | pInt->ulKeyframesNeeded--; |
2393 | } |
2394 | bSkipPacket = FALSE; |
2395 | } else { |
2396 | /* |
2397 | * We need keyframes for this stream and |
2398 | * this is not a keyframe. |
2399 | */ |
2400 | bSkipPacket = TRUE; |
2401 | /* Seek past the data of this packet */ |
2402 | rm_parseri_file_seek(pInt, |
2403 | hdr.length - hdr.header_len, |
2404 | HX_SEEK_ORIGIN_CUR); |
2405 | } |
2406 | } else { |
2407 | bSkipPacket = FALSE; |
2408 | } |
2409 | } |
2410 | } else { |
2411 | /* Got a stream number we didn't expect */ |
2412 | retVal = HXR_CORRUPT_FILE; |
2413 | /* Call back to error interface */ |
2414 | rm_parseri_error(pInt, retVal, "Unexpected stream number in packet."); |
2415 | } |
2416 | } |
2417 | } while (HX_SUCCEEDED(retVal) && bSkipPacket); |
2418 | /* Have we found a packet? */ |
2419 | if (HX_SUCCEEDED(retVal)) { |
2420 | /* Get the last packet time and rule for this stream */ |
2421 | ulLastPacketTime = pInt->pStreamInfo[ulStreamNum].ulLastTimeStamp; |
2422 | ulLastRule = pInt->pStreamInfo[ulStreamNum].ulLastRule; |
2423 | /* Determine the ASM rules and flags */ |
2424 | if (pInt->pStreamInfo[ulStreamNum].bIsRealVideo) { |
2425 | /* |
2426 | * If the time stamp for this packet is different from |
2427 | * the timestamp of the next packet and either this packet |
2428 | * is a keyframe or the last packet was a keyframe we can |
2429 | * switch on this packet |
2430 | */ |
2431 | if (hdr.timestamp != ulLastPacketTime && |
2432 | (hdr.flags & HX_KEYFRAME_FLAG || |
2433 | ulLastRule == HX_KEYFRAME_RULE || |
2434 | ulLastRule == HX_THINNING_RULE)) { |
2435 | ulASMFlags = HX_ASM_SWITCH_ON | HX_ASM_SWITCH_OFF; |
2436 | } else if (hdr.timestamp != ulLastPacketTime) { |
2437 | /* If this is part of a different frame, we can switch off */ |
2438 | ulASMFlags = HX_ASM_SWITCH_OFF; |
2439 | } else { |
2440 | /* |
2441 | * If this packet has the same timestamp as the previous |
2442 | * packet we cannot switch on or switch off here. |
2443 | */ |
2444 | ulASMFlags = 0; |
2445 | } |
2446 | /* Assign the ASM rule */ |
2447 | ulASMRule = (hdr.flags & HX_KEYFRAME_FLAG ? HX_KEYFRAME_RULE : HX_NONKEYFRAME_RULE); |
2448 | } else if (pInt->pStreamInfo[ulStreamNum].bIsRealAudio) { |
2449 | /* |
2450 | * For audio, the first block of the super block and the second block |
2451 | * of the super block are ON since the first block and the second block |
2452 | * are the first packets on their respective rule numbers |
2453 | */ |
2454 | if (hdr.flags & HX_KEYFRAME_FLAG || ulLastRule == HX_KEYFRAME_RULE) { |
2455 | ulASMFlags = HX_ASM_SWITCH_ON | HX_ASM_SWITCH_OFF; |
2456 | } else { |
2457 | ulASMFlags = HX_ASM_SWITCH_OFF; |
2458 | } |
2459 | /* Assign the ASM rule */ |
2460 | ulASMRule = (hdr.flags & HX_KEYFRAME_FLAG ? HX_KEYFRAME_RULE : HX_NONKEYFRAME_RULE); |
2461 | } else { |
2462 | /* Assign the ASM flags */ |
2463 | ulASMFlags = HX_ASM_SWITCH_OFF; |
2464 | ulASMFlags |= (hdr.flags & HX_KEYFRAME_FLAG ? HX_ASM_SWITCH_ON : 0); |
2465 | /* Is this an event stream or file version 0? */ |
2466 | if (pInt->pStreamInfo[ulStreamNum].bIsRealEvent || |
2467 | pInt->fileHdr.file_version == 0) { |
2468 | ulASMRule = (hdr.flags & HX_KEYFRAME_FLAG ? HX_KEYFRAME_RULE : HX_NONKEYFRAME_RULE); |
2469 | } else { |
2470 | /* |
2471 | * In case of non-RM streams version 1 or later, the rule |
2472 | * number is recorded directly into the upper 8 bits of the |
2473 | * flags field (packet_group) |
2474 | */ |
2475 | ulASMRule = (UINT32)((hdr.flags >> 8) & 0x00FF); |
2476 | } |
2477 | } |
2478 | /* Set the return value */ |
2479 | retVal = HXR_OUTOFMEMORY; |
2480 | /* Allocate space for the rm_packet */ |
2481 | pPacket = (rm_packet*) rm_parseri_malloc(pInt, sizeof(rm_packet)); |
2482 | if (pPacket) { |
2483 | /* NULL out the packet */ |
2484 | memset(pPacket, 0, sizeof(rm_packet)); |
2485 | /* Compute the data size */ |
2486 | ulDataSize = hdr.length - hdr.header_len; |
2487 | /* Allocate space for the data */ |
2488 | pPacket->pData = (BYTE*) rm_parseri_malloc(pInt, ulDataSize); |
2489 | if (pPacket->pData) { |
2490 | /* Read the data into the buffer */ |
2491 | ulBytesRead = rm_parseri_file_read_buffer(pInt, pPacket->pData, ulDataSize); |
2492 | if (ulBytesRead == ulDataSize) { |
2493 | /* Assign the packet parameters */ |
2494 | pPacket->ulTime = hdr.timestamp; |
2495 | pPacket->usStream = (UINT16) ulStreamNum; |
2496 | pPacket->usASMFlags = (UINT16) ulASMFlags; |
2497 | pPacket->ucASMRule = (BYTE) ulASMRule; |
2498 | pPacket->ucLost = FALSE; |
2499 | pPacket->usDataLen = (UINT16) ulDataSize; |
2500 | /* Update the last timestamp and rule */ |
2501 | pInt->pStreamInfo[ulStreamNum].ulLastTimeStamp = hdr.timestamp; |
2502 | pInt->pStreamInfo[ulStreamNum].ulLastRule = ulASMRule; |
2503 | /* Compute the file offset of this packet */ |
2504 | ulPacketOffset = pInt->ulCurFileOffset - |
2505 | ulDataSize - hdr.header_len; |
2506 | /* Update the seek table */ |
2507 | rm_parseri_update_seek_table(pInt, |
2508 | ulStreamNum, |
2509 | hdr.timestamp, |
2510 | ulPacketOffset, |
2511 | hdr.flags); |
2512 | /* Assign the out parameter */ |
2513 | *ppPacket = pPacket; |
2514 | /* Clear the return value */ |
2515 | retVal = HXR_OK; |
2516 | } else { |
2517 | /* Could not read packet data */ |
2518 | retVal = HXR_READ_ERROR; |
2519 | /* Call back to error interface */ |
2520 | rm_parseri_error(pInt, retVal, "Could not read packet data."); |
2521 | } |
2522 | } |
2523 | if (retVal != HXR_OK) { |
2524 | /* Free the packet data */ |
2525 | if (pPacket->pData) { |
2526 | rm_parseri_free(pInt, pPacket->pData); |
2527 | pPacket->pData = HXNULL; |
2528 | } |
2529 | /* Free the packet */ |
2530 | rm_parseri_free(pInt, pPacket); |
2531 | pPacket = HXNULL; |
2532 | } |
2533 | } |
2534 | } |
2535 | } else { |
2536 | /* We are finished reading packets from this chunk */ |
2537 | retVal = HXR_AT_END; |
2538 | } |
2539 | } |
2540 | |
2541 | return retVal; |
2542 | } |
2543 | |
2544 | UINT32 rm_parseri_file_read(rm_parser_internal* pInt, UINT32 ulBytesToRead, UINT32 ulReadBufferOffset) |
2545 | { |
2546 | UINT32 ulRet = 0; |
2547 | // DataSrc_t *ds = pInt->pUserRead; |
2548 | UINT8 err; |
2549 | |
2550 | if (pInt && pInt->fpRead) { |
2551 | /* Make sure our read buffer is big enough */ |
2552 | HX_RESULT rv = rm_enforce_buffer_min_size(pInt->pUserMem, |
2553 | pInt->fpMalloc, |
2554 | pInt->fpFree, |
2555 | &pInt->pReadBuffer, |
2556 | &pInt->ulReadBufferSize, |
2557 | ulReadBufferOffset + ulBytesToRead); |
2558 | if (rv == HXR_OK) { |
2559 | // if (ds&&ds->streaming_sem) |
2560 | // AVMutexPend(ds->streaming_sem, 0, &err); |
2561 | /* Seek the file */ |
2562 | pInt->fpSeek(pInt->pUserRead, pInt->ulCurFileOffset, HX_SEEK_ORIGIN_SET); |
2563 | /* Read in ulBytesToRead bytes */ |
2564 | ulRet = pInt->fpRead(pInt->pUserRead, |
2565 | pInt->pReadBuffer + ulReadBufferOffset, |
2566 | ulBytesToRead); |
2567 | /* Save the number of bytes in read buffer */ |
2568 | pInt->ulNumBytesRead = ulRet + ulReadBufferOffset; |
2569 | /* Advance the current file offset */ |
2570 | pInt->ulCurFileOffset += ulRet; |
2571 | // if (ds&&ds->streaming_sem) |
2572 | // AVMutexPost(ds->streaming_sem); |
2573 | } |
2574 | } |
2575 | |
2576 | return ulRet; |
2577 | } |
2578 | |
2579 | UINT32 rm_parseri_file_read_buffer(rm_parser_internal* pInt, BYTE* pBuf, UINT32 ulBytesToRead) |
2580 | { |
2581 | UINT32 ulRet = 0; |
2582 | // DataSrc_t *ds = pInt->pUserRead; |
2583 | UINT8 err; |
2584 | |
2585 | if (pInt && pInt->fpRead) { |
2586 | // if (ds&&ds->streaming_sem) |
2587 | // AVMutexPend(ds->streaming_sem, 0, &err); |
2588 | /* Seek the file */ |
2589 | pInt->fpSeek(pInt->pUserRead, pInt->ulCurFileOffset, HX_SEEK_ORIGIN_SET); |
2590 | /* Read in ulBytesToRead bytes */ |
2591 | ulRet = pInt->fpRead(pInt->pUserRead, pBuf, ulBytesToRead); |
2592 | /* Advance the current file offset */ |
2593 | pInt->ulCurFileOffset += ulRet; |
2594 | // if (ds&&ds->streaming_sem) |
2595 | // AVMutexPost(ds->streaming_sem); |
2596 | } |
2597 | |
2598 | return ulRet; |
2599 | } |
2600 | |
2601 | void rm_parseri_file_seek(rm_parser_internal* pInt, UINT32 ulOffset, UINT32 ulOrigin) |
2602 | { |
2603 | if (pInt && pInt->fpSeek) { |
2604 | /* Seek the file */ |
2605 | pInt->fpSeek(pInt->pUserRead, ulOffset, ulOrigin); |
2606 | /* Update the current file offset */ |
2607 | if (ulOrigin == HX_SEEK_ORIGIN_SET) { |
2608 | pInt->ulCurFileOffset = ulOffset; |
2609 | } else if (ulOrigin == HX_SEEK_ORIGIN_CUR) { |
2610 | pInt->ulCurFileOffset += ulOffset; |
2611 | } else if (ulOrigin == HX_SEEK_ORIGIN_END) { |
2612 | /* |
2613 | * XXXMEH - don't know file size, so not sure what to do here. |
2614 | * We could require ftell-like functionality, or we could |
2615 | * require some type of fstat-like functionality. |
2616 | */ |
2617 | rm_parseri_error(pInt, HXR_NOT_SUPPORTED, "File seek with end origin attempted - not suported."); |
2618 | } |
2619 | } |
2620 | } |
2621 | |
2622 | void rm_parseri_set_stream_size(rm_parser_internal* pInt, UINT32 stream_size) |
2623 | { |
2624 | if (pInt) { |
2625 | UINT32 i = 0; |
2626 | for (i = 0; i < pInt->ulNumStreams; i++) { |
2627 | if (pInt->pStreamHdr[i].ulStreamSize == RM_PARSER_DATA_CHUNK_HEADER_SIZE) { |
2628 | pInt->pStreamHdr[i].ulStreamSize = stream_size; |
2629 | } |
2630 | if (pInt->pDataHdr[i].size == RM_PARSER_DATA_CHUNK_HEADER_SIZE) { |
2631 | pInt->pDataHdr[i].size = stream_size; |
2632 | } |
2633 | } |
2634 | } |
2635 | } |
2636 | |
2637 | HX_RESULT rm_parseri_copy_stream_header(rm_parser_internal* pInt, UINT32 i, rm_stream_header* pHdr) |
2638 | { |
2639 | HX_RESULT retVal = HXR_FAIL; |
2640 | |
2641 | if (pInt && pHdr && i < pInt->ulNumStreams && pInt->pStreamHdr) { |
2642 | UINT32 j = 0; |
2643 | UINT32 ulSize = 0; |
2644 | /* Clean up any existing header */ |
2645 | rm_parseri_cleanup_stream_header(pInt, pHdr); |
2646 | /* Copy the hard-coded members */ |
2647 | pHdr->ulStreamNumber = pInt->pStreamHdr[i].ulStreamNumber; |
2648 | pHdr->ulMaxBitRate = pInt->pStreamHdr[i].ulMaxBitRate; |
2649 | pHdr->ulAvgBitRate = pInt->pStreamHdr[i].ulAvgBitRate; |
2650 | pHdr->ulMaxPacketSize = pInt->pStreamHdr[i].ulMaxPacketSize; |
2651 | pHdr->ulAvgPacketSize = pInt->pStreamHdr[i].ulAvgPacketSize; |
2652 | pHdr->ulDuration = pInt->pStreamHdr[i].ulDuration; |
2653 | pHdr->ulPreroll = pInt->pStreamHdr[i].ulPreroll; |
2654 | pHdr->ulStartTime = pInt->pStreamHdr[i].ulStartTime; |
2655 | pHdr->ulStartOffset = pInt->pStreamHdr[i].ulStartOffset; |
2656 | pHdr->ulStreamSize = pInt->pStreamHdr[i].ulStreamSize; |
2657 | pHdr->pMimeType = copy_string(pInt->pUserMem, pInt->fpMalloc, |
2658 | pInt->pStreamHdr[i].pMimeType); |
2659 | pHdr->pStreamName = copy_string(pInt->pUserMem, pInt->fpMalloc, |
2660 | pInt->pStreamHdr[i].pStreamName); |
2661 | pHdr->pOpaqueData = copy_buffer(pInt->pUserMem, pInt->fpMalloc, |
2662 | pInt->pStreamHdr[i].pOpaqueData, |
2663 | pInt->pStreamHdr[i].ulOpaqueDataLen); |
2664 | if ((!pInt->pStreamHdr[i].pMimeType || pHdr->pMimeType) && |
2665 | (!pInt->pStreamHdr[i].pStreamName || pHdr->pStreamName) && |
2666 | (!pInt->pStreamHdr[i].pOpaqueData || pHdr->pOpaqueData)) { |
2667 | /* Copy the properties array */ |
2668 | if (pInt->pStreamHdr[i].ulNumProperties && |
2669 | pInt->pStreamHdr[i].pProperty) { |
2670 | /* Allocate space for the property array */ |
2671 | ulSize = pInt->pStreamHdr[i].ulNumProperties * sizeof(rm_property); |
2672 | pHdr->pProperty = (rm_property*) rm_parseri_malloc(pInt, ulSize); |
2673 | if (pHdr->pProperty) { |
2674 | /* NULL out the array */ |
2675 | memset(pHdr->pProperty, 0, ulSize); |
2676 | /* Copy each of the properties */ |
2677 | retVal = HXR_OK; |
2678 | for (j = 0; j < pInt->pStreamHdr[i].ulNumProperties && retVal == HXR_OK; j++) { |
2679 | retVal = rm_parseri_set_rm_property(pInt, &pHdr->pProperty[j], |
2680 | pInt->pStreamHdr[i].pProperty[j].pName, |
2681 | pInt->pStreamHdr[i].pProperty[j].ulType, |
2682 | (void*) pInt->pStreamHdr[i].pProperty[j].pValue, |
2683 | pInt->pStreamHdr[i].pProperty[j].ulValueLen); |
2684 | } |
2685 | if (retVal == HXR_OK) { |
2686 | /* Assign the number of properties */ |
2687 | pHdr->ulNumProperties = pInt->pStreamHdr[i].ulNumProperties; |
2688 | } |
2689 | } |
2690 | } |
2691 | } |
2692 | } |
2693 | |
2694 | return retVal; |
2695 | } |
2696 | |
2697 | HX_RESULT rm_parseri_update_seek_table(rm_parser_internal* pInt, UINT32 ulStreamNum, |
2698 | UINT32 ulTime, UINT32 ulOffset, UINT32 ulFlags) |
2699 | { |
2700 | HX_RESULT retVal = HXR_FAIL; |
2701 | |
2702 | if (pInt && pInt->pStreamInfo && ulStreamNum < pInt->ulNumStreams) { |
2703 | struct rm_seek_table* pTable = &pInt->pStreamInfo[ulStreamNum].seekTable; |
2704 | if (pTable) { |
2705 | /* Was this a keyframe packet? */ |
2706 | if (ulFlags & HX_KEYFRAME_FLAG) { |
2707 | /* Do we have space left in the table? */ |
2708 | if (pTable->pEntry && pTable->ulNumEntries < pTable->ulMaxEntries) { |
2709 | /* |
2710 | * If this is the first entry; or if this |
2711 | * time is at least ulTimeGranularity greater |
2712 | * than the last time added, then make an entry. |
2713 | */ |
2714 | if (!pTable->ulNumEntries || |
2715 | (ulTime > pTable->ulLastTime && |
2716 | ulTime - pTable->ulLastTime > pTable->ulTimeGranularity)) { |
2717 | /* Update the last time */ |
2718 | pTable->ulLastTime = ulTime; |
2719 | /* Update the time range this table covers */ |
2720 | if (ulTime > pTable->ulRangeTime) { |
2721 | pTable->ulRangeTime = ulTime; |
2722 | } |
2723 | /* Make the new entry */ |
2724 | pTable->pEntry[pTable->ulNumEntries].ulTime = ulTime; |
2725 | pTable->pEntry[pTable->ulNumEntries].ulOffset = ulOffset; |
2726 | /* Increment the number of entries */ |
2727 | pTable->ulNumEntries++; |
2728 | /* Clear the return value */ |
2729 | retVal = HXR_OK; |
2730 | } |
2731 | } |
2732 | } else { |
2733 | /* |
2734 | * This is not a keyframe, so we don't have to |
2735 | * make an entry in the table, but we do need to |
2736 | * update the time range that it covers. |
2737 | */ |
2738 | if (ulTime > pTable->ulRangeTime) { |
2739 | pTable->ulRangeTime = ulTime; |
2740 | } |
2741 | /* Clear the return value */ |
2742 | retVal = HXR_OK; |
2743 | } |
2744 | } |
2745 | } |
2746 | |
2747 | return retVal; |
2748 | } |
2749 | |
2750 | HX_RESULT rm_parseri_update_time_range(rm_parser_internal* pInt, UINT32 ulStreamNum, |
2751 | UINT32 ulTime) |
2752 | { |
2753 | HX_RESULT retVal = HXR_FAIL; |
2754 | |
2755 | if (pInt && pInt->pStreamInfo && ulStreamNum < pInt->ulNumStreams) { |
2756 | /* Get the seek table for this stream */ |
2757 | struct rm_seek_table* pTable = &pInt->pStreamInfo[ulStreamNum].seekTable; |
2758 | if (pTable) { |
2759 | /* Update the time range this table covers */ |
2760 | if (ulTime > pTable->ulRangeTime) { |
2761 | pTable->ulRangeTime = ulTime; |
2762 | } |
2763 | /* Clear the return value */ |
2764 | retVal = HXR_OK; |
2765 | } |
2766 | } |
2767 | |
2768 | return retVal; |
2769 | } |
2770 | |
2771 | HX_RESULT rm_parseri_search_all_seek_tables(rm_parser_internal* pInt, UINT32 ulSeekTime, |
2772 | UINT32* pulFoundTime, UINT32* pulFoundOffset) |
2773 | { |
2774 | HX_RESULT retVal = HXR_FAIL; |
2775 | |
2776 | if (pInt && pulFoundTime && pulFoundOffset && |
2777 | pInt->ulNumStreams && pInt->pStreamInfo) { |
2778 | /* Initialize local variables */ |
2779 | UINT32 ulMaxTime = 0; |
2780 | UINT32 ulMaxOffset = 0; |
2781 | UINT32 i = 0; |
2782 | UINT32 pulFoundIndex; |
2783 | HX_RESULT status = HXR_FAIL; |
2784 | /* Search the streams */ |
2785 | for (i = 0; i < pInt->ulNumStreams; i++) { |
2786 | /* Get the stream info struct */ |
2787 | struct rm_stream_info* pInfo = &pInt->pStreamInfo[i]; |
2788 | if (pInfo) { |
2789 | status = rm_parseri_search_seek_table(&pInfo->seekTable, |
2790 | ulSeekTime, |
2791 | 0, |
2792 | &pInfo->keyFramePacket.ulTimestamp, |
2793 | &pInfo->keyFramePacket.ulFileOffset, |
2794 | &pulFoundIndex); |
2795 | if (status == HXR_OK) { |
2796 | pInfo->keyFramePacket.bValid = TRUE; |
2797 | if (pInfo->keyFramePacket.ulTimestamp > ulMaxTime) { |
2798 | ulMaxTime = pInfo->keyFramePacket.ulTimestamp; |
2799 | } |
2800 | if (pInfo->keyFramePacket.ulFileOffset > ulMaxOffset) { |
2801 | ulMaxOffset = pInfo->keyFramePacket.ulFileOffset; |
2802 | } |
2803 | } |
2804 | /* |
2805 | * If at least one stream succeeds, the overall search |
2806 | * succeeds. Note that rm_parseri_search_seek_table() can |
2807 | * return either HXR_AT_END or HXR_OK, both of which |
2808 | * return HX_SUCCEEDED() == TRUE. That's why we have to |
2809 | * specifically check for status == HXR_OK, as opposed |
2810 | * to just HX_SUCCEEDED(status). |
2811 | */ |
2812 | if (HX_FAILED(retVal) || |
2813 | (HX_SUCCEEDED(retVal) && status == HXR_OK)) { |
2814 | retVal = status; |
2815 | } |
2816 | } |
2817 | } |
2818 | if (HX_SUCCEEDED(retVal)) { |
2819 | *pulFoundTime = ulMaxTime; |
2820 | *pulFoundOffset = ulMaxOffset; |
2821 | } |
2822 | } |
2823 | |
2824 | return retVal; |
2825 | } |
2826 | |
2827 | HX_RESULT rm_parseri_search_seek_tables(rm_parser_internal* pInt, INT32 lStreamNumber, UINT32 ulSeekTime, INT32 lDirection, |
2828 | UINT32* pulFoundTime, UINT32* pulFoundOffset, UINT32* pulFoundIndex) |
2829 | { |
2830 | HX_RESULT retVal = HXR_FAIL; |
2831 | |
2832 | if (pInt && pulFoundTime && pulFoundOffset && |
2833 | pInt->ulNumStreams && pInt->pStreamInfo) { |
2834 | /* Initialize local variables */ |
2835 | UINT32 ulMinTime = 0xffffffff; |
2836 | UINT32 ulMinOffset = 0xffffffff; |
2837 | UINT32 i = 0; |
2838 | HX_RESULT status = HXR_FAIL; |
2839 | struct rm_stream_info* pInfo = &pInt->pStreamInfo[lStreamNumber]; |
2840 | /* Search the streams */ |
2841 | { |
2842 | /* Get the stream info struct */ |
2843 | if (pInfo) { |
2844 | retVal = rm_parseri_search_seek_table(&pInfo->seekTable, |
2845 | ulSeekTime, |
2846 | lDirection, |
2847 | &pInfo->keyFramePacket.ulTimestamp, |
2848 | &pInfo->keyFramePacket.ulFileOffset, |
2849 | pulFoundIndex); |
2850 | if (retVal == HXR_OK) { |
2851 | pInfo->keyFramePacket.bValid = TRUE; |
2852 | } |
2853 | } |
2854 | } |
2855 | if (retVal == HXR_OK) { |
2856 | *pulFoundTime = pInfo->keyFramePacket.ulTimestamp; |
2857 | *pulFoundOffset = pInfo->keyFramePacket.ulFileOffset; |
2858 | } |
2859 | } |
2860 | |
2861 | return retVal; |
2862 | } |
2863 | |
2864 | HX_RESULT rm_parseri_search_seek_table(struct rm_seek_table* pTable, UINT32 ulSeekTime, INT32 lDirection, |
2865 | UINT32* pulFoundTime, UINT32* pulFoundOffset, UINT32 *pulFoundIndex) |
2866 | { |
2867 | HX_RESULT retVal = HXR_FAIL; |
2868 | |
2869 | if (pTable && pulFoundTime && pulFoundOffset && pTable->ulNumEntries) { |
2870 | /* Estimate index to seek from */ |
2871 | UINT32 ulTableIdx = ulSeekTime / pTable->ulTimeGranularity; |
2872 | /* |
2873 | * If we've over-estimated, set the index at the |
2874 | * last entry in the table. |
2875 | */ |
2876 | if (ulTableIdx >= pTable->ulNumEntries) { |
2877 | ulTableIdx = pTable->ulNumEntries - 1; |
2878 | } |
2879 | /* Scan forward in the table */ |
2880 | while (((ulTableIdx + 1) < (pTable->ulNumEntries - 1)) && |
2881 | (pTable->pEntry[ulTableIdx + 1].ulTime < ulSeekTime)) { |
2882 | ulTableIdx++; |
2883 | } |
2884 | /* Scan backwards in the table */ |
2885 | while ((ulTableIdx > 0) && |
2886 | (pTable->pEntry[ulTableIdx].ulTime > ulSeekTime)) { |
2887 | ulTableIdx--; |
2888 | } |
2889 | if (lDirection) { |
2890 | if ((lDirection > 0) && (ulTableIdx < pTable->ulNumEntries - 1)) { |
2891 | ulTableIdx++; |
2892 | } else if ((lDirection < 0) && (ulTableIdx > 0)) { |
2893 | ulTableIdx--; |
2894 | } |
2895 | } |
2896 | /* Report results */ |
2897 | *pulFoundTime = pTable->pEntry[ulTableIdx].ulTime; |
2898 | *pulFoundOffset = pTable->pEntry[ulTableIdx].ulOffset; |
2899 | /* Set the return value */ |
2900 | retVal = (ulSeekTime > pTable->ulRangeTime ? HXR_AT_END : HXR_OK); |
2901 | } |
2902 | |
2903 | return retVal; |
2904 | } |
2905 | |
2906 | HX_RESULT rm_parseri_search_index_chunk(rm_parser_internal* pInt, UINT32 ulSeekTime) |
2907 | { |
2908 | HX_RESULT retVal = HXR_FAIL; |
2909 | |
2910 | if (pInt && pInt->propHdr.index_offset && pInt->pStreamInfo && |
2911 | pInt->ulNumStreams) { |
2912 | /* Initialize local variables */ |
2913 | struct rm_index_hdr hdr; |
2914 | struct rm_index_rec rec; |
2915 | UINT32 ulChunkID = 0; |
2916 | UINT32 ulStreamNum = 0; |
2917 | UINT32 i = 0; |
2918 | UINT32 ulIndexOffset = pInt->propHdr.index_offset; |
2919 | /* Mark all keyframe packets as invalid */ |
2920 | for (i = 0; i < pInt->ulNumStreams; i++) { |
2921 | pInt->pStreamInfo[i].keyFramePacket.bValid = FALSE; |
2922 | } |
2923 | /* Clear the return value */ |
2924 | retVal = HXR_OK; |
2925 | /* Loop through all the index chunks */ |
2926 | while (HX_SUCCEEDED(retVal) && |
2927 | ulIndexOffset && |
2928 | !rm_parseri_is_all_keyframes_found(pInt)) { |
2929 | /* Seek the file to the next index chunk */ |
2930 | rm_parseri_file_seek(pInt, ulIndexOffset, HX_SEEK_ORIGIN_SET); |
2931 | /* Read the index header */ |
2932 | retVal = rm_parseri_read_next_header(pInt, &ulChunkID); |
2933 | if (retVal == HXR_OK) { |
2934 | /* Assume the worst */ |
2935 | retVal = HXR_FAIL; |
2936 | /* Make sure this is an INDX header */ |
2937 | if (ulChunkID == RM_INDEX_OBJECT) { |
2938 | /* Parse the index header */ |
2939 | retVal = rm_parseri_unpack_index_hdr(pInt, &hdr); |
2940 | if (retVal == HXR_OK) { |
2941 | /* |
2942 | * Translate the stream number. If the |
2943 | * stream number doesn't translate, then |
2944 | * we will not consider it an error - we'll |
2945 | * just go on to the next index chunk. |
2946 | */ |
2947 | ulStreamNum = rm_parseri_translate_stream_number(pInt, hdr.stream_num); |
2948 | if (ulStreamNum != RM_NO_STREAM_SET) { |
2949 | /* Get the rm_keyframe_packet struct */ |
2950 | struct rm_keyframe_packet* pKey = |
2951 | &pInt->pStreamInfo[ulStreamNum].keyFramePacket; |
2952 | /* Read all the index records in this chunk */ |
2953 | for (i = 0; i < hdr.num_recs && retVal == HXR_OK; i++) { |
2954 | retVal = rm_parseri_read_next_index_rec(pInt, &rec); |
2955 | if (retVal == HXR_OK) { |
2956 | /* |
2957 | * Set this record into the on-the-fly |
2958 | * seek table. |
2959 | */ |
2960 | rm_parseri_update_seek_table(pInt, |
2961 | ulStreamNum, |
2962 | rec.timestamp, |
2963 | rec.offset, |
2964 | HX_KEYFRAME_FLAG); |
2965 | /* |
2966 | * Is the timestamp of the record |
2967 | * greater than or equal to the seek time? |
2968 | */ |
2969 | if (rec.timestamp >= ulSeekTime) { |
2970 | /* Do we have a valid keyframe for this stream? */ |
2971 | if (!pKey->bValid) { |
2972 | pKey->bValid = TRUE; |
2973 | pKey->ulFileOffset = rec.offset; |
2974 | pKey->ulTimestamp = rec.timestamp; |
2975 | } |
2976 | /* |
2977 | * Now we can stop looking at index records |
2978 | * for this stream |
2979 | */ |
2980 | break; |
2981 | } else { |
2982 | /* Save the keyframe info */ |
2983 | pKey->bValid = TRUE; |
2984 | pKey->ulFileOffset = rec.offset; |
2985 | pKey->ulTimestamp = rec.timestamp; |
2986 | } |
2987 | } |
2988 | } |
2989 | } |
2990 | /* |
2991 | * Set the next index header. If there are |
2992 | * no more index chunks, next_index_hdr will |
2993 | * be zero. |
2994 | */ |
2995 | ulIndexOffset = hdr.next_index_hdr; |
2996 | } |
2997 | } |
2998 | } |
2999 | } |
3000 | /* Find the first keyframe */ |
3001 | if (HX_SUCCEEDED(retVal)) { |
3002 | retVal = rm_parseri_find_first_keyframe(pInt); |
3003 | } |
3004 | } |
3005 | |
3006 | return retVal; |
3007 | } |
3008 | |
3009 | HX_RESULT rm_parseri_build_seek_table(rm_parser_internal* pInt) |
3010 | { |
3011 | HX_RESULT retVal = HXR_FAIL; |
3012 | |
3013 | // not support seek without Interleaved Streams now |
3014 | if (pInt->ulInterleavedStreamsFlag == 0) { |
3015 | return HXR_FAIL; |
3016 | } |
3017 | |
3018 | if (pInt && pInt->propHdr.index_offset && pInt->pStreamInfo && |
3019 | pInt->ulNumStreams) { |
3020 | /* Initialize local variables */ |
3021 | struct rm_index_hdr hdr; |
3022 | struct rm_index_rec rec; |
3023 | UINT32 ulChunkID = 0; |
3024 | UINT32 ulStreamNum = 0; |
3025 | UINT32 i = 0; |
3026 | UINT32 ulIndexOffset = pInt->propHdr.index_offset; |
3027 | /* Mark all keyframe packets as invalid */ |
3028 | for (i = 0; i < pInt->ulNumStreams; i++) { |
3029 | pInt->pStreamInfo[i].keyFramePacket.bValid = FALSE; |
3030 | } |
3031 | /* Clear the return value */ |
3032 | retVal = HXR_OK; |
3033 | /* Loop through all the index chunks */ |
3034 | while (HX_SUCCEEDED(retVal) && |
3035 | ulIndexOffset && |
3036 | !rm_parseri_is_all_keyframes_found(pInt)) { |
3037 | /* Seek the file to the next index chunk */ |
3038 | rm_parseri_file_seek(pInt, ulIndexOffset, HX_SEEK_ORIGIN_SET); |
3039 | /* Read the index header */ |
3040 | retVal = rm_parseri_read_next_header(pInt, &ulChunkID); |
3041 | if (retVal == HXR_OK) { |
3042 | /* Assume the worst */ |
3043 | retVal = HXR_FAIL; |
3044 | /* Make sure this is an INDX header */ |
3045 | if (ulChunkID == RM_INDEX_OBJECT) { |
3046 | /* Parse the index header */ |
3047 | retVal = rm_parseri_unpack_index_hdr(pInt, &hdr); |
3048 | if (retVal == HXR_OK) { |
3049 | /* |
3050 | * Translate the stream number. If the |
3051 | * stream number doesn't translate, then |
3052 | * we will not consider it an error - we'll |
3053 | * just go on to the next index chunk. |
3054 | */ |
3055 | ulStreamNum = rm_parseri_translate_stream_number(pInt, hdr.stream_num); |
3056 | if (ulStreamNum != RM_NO_STREAM_SET) { |
3057 | /* Get the rm_keyframe_packet struct */ |
3058 | struct rm_keyframe_packet* pKey = |
3059 | &pInt->pStreamInfo[ulStreamNum].keyFramePacket; |
3060 | /* Read all the index records in this chunk */ |
3061 | for (i = 0; i < hdr.num_recs && retVal == HXR_OK; i++) { |
3062 | retVal = rm_parseri_read_next_index_rec(pInt, &rec); |
3063 | if (retVal == HXR_OK) { |
3064 | /* |
3065 | * Set this record into the on-the-fly |
3066 | * seek table. |
3067 | */ |
3068 | rm_parseri_update_seek_table(pInt, |
3069 | ulStreamNum, |
3070 | rec.timestamp, |
3071 | rec.offset, |
3072 | HX_KEYFRAME_FLAG); |
3073 | { |
3074 | /* Save the keyframe info */ |
3075 | pKey->bValid = TRUE; |
3076 | pKey->ulFileOffset = rec.offset; |
3077 | pKey->ulTimestamp = rec.timestamp; |
3078 | } |
3079 | } |
3080 | } |
3081 | } |
3082 | /* |
3083 | * Set the next index header. If there are |
3084 | * no more index chunks, next_index_hdr will |
3085 | * be zero. |
3086 | */ |
3087 | ulIndexOffset = hdr.next_index_hdr; |
3088 | } |
3089 | } |
3090 | } |
3091 | } |
3092 | } |
3093 | |
3094 | return retVal; |
3095 | } |
3096 | |
3097 | HX_RESULT rm_parseri_seek(rm_parser_internal* pInt, UINT32 ulSeekTime) |
3098 | { |
3099 | HX_RESULT retVal = HXR_FAIL; |
3100 | |
3101 | if (pInt && pInt->ulNumStreams && pInt->pStreamInfo) { |
3102 | /* Initialize local variables */ |
3103 | UINT32 i = 0; |
3104 | HX_RESULT status = HXR_OK; |
3105 | UINT32 ulFoundTime = 0; |
3106 | UINT32 ulDataOffset = 0; |
3107 | /* Clear out stream state */ |
3108 | for (i = 0; i < pInt->ulNumStreams; i++) { |
3109 | pInt->pStreamInfo[i].bStreamDone = FALSE; |
3110 | pInt->pStreamInfo[i].ulLastTimeStamp = 0xFFFFFFFF; |
3111 | pInt->pStreamInfo[i].keyFramePacket.bValid = FALSE; |
3112 | } |
3113 | /* First we try to search the on-the-fly seek table */ |
3114 | status = rm_parseri_search_all_seek_tables(pInt, ulSeekTime, |
3115 | &ulFoundTime, &ulDataOffset); |
3116 | if (status == HXR_OK) { |
3117 | retVal = rm_parseri_find_first_packet_after_seek_time(pInt, |
3118 | ulSeekTime, |
3119 | ulDataOffset); |
3120 | } else if (pInt->propHdr.index_offset && ulSeekTime) { |
3121 | /* |
3122 | * Try to find the offset via the index chunks |
3123 | * at the end of the file |
3124 | */ |
3125 | retVal = rm_parseri_search_index_chunk(pInt, ulSeekTime); |
3126 | } else if (status == HXR_AT_END) { |
3127 | /* |
3128 | * The on-the-fly seek table returned HXR_AT_END, |
3129 | * which means the seek time was past it's range, |
3130 | * so it returned the last entry it had in the table. |
3131 | * If we can't use the index table at the end of the |
3132 | * file, then we'll use this - it's better than starting |
3133 | * at the beginning of the data chunk. |
3134 | */ |
3135 | retVal = rm_parseri_find_first_packet_after_seek_time(pInt, |
3136 | ulSeekTime, |
3137 | ulDataOffset); |
3138 | } else { |
3139 | /* |
3140 | * Compute the offset of the first packet |
3141 | * after the data chunk. |
3142 | */ |
3143 | ulDataOffset = pInt->propHdr.data_offset + |
3144 | RM_PARSER_DATA_CHUNK_HEADER_SIZE; |
3145 | /* Seek from the beginning of the data chunk */ |
3146 | retVal = rm_parseri_find_first_packet_after_seek_time(pInt, |
3147 | ulSeekTime, |
3148 | ulDataOffset); |
3149 | } |
3150 | } |
3151 | |
3152 | return retVal; |
3153 | } |
3154 | |
3155 | HXBOOL rm_parseri_is_all_keyframes_found(rm_parser_internal* pInt) |
3156 | { |
3157 | HXBOOL bRet = FALSE; |
3158 | |
3159 | if (pInt && pInt->ulNumStreams && pInt->pStreamInfo) { |
3160 | /* Init local variables */ |
3161 | UINT32 i = 0; |
3162 | /* Assume we have found all of them */ |
3163 | bRet = TRUE; |
3164 | /* Look through all streams */ |
3165 | for (i = 0; i < pInt->ulNumStreams; i++) { |
3166 | if (!pInt->pStreamInfo[i].keyFramePacket.bValid) { |
3167 | bRet = FALSE; |
3168 | break; |
3169 | } |
3170 | } |
3171 | } |
3172 | |
3173 | return bRet; |
3174 | } |
3175 | |
3176 | HXBOOL rm_parseri_is_a_keyframe_found(rm_parser_internal* pInt) |
3177 | { |
3178 | HXBOOL bRet = FALSE; |
3179 | |
3180 | if (pInt && pInt->ulNumStreams && pInt->pStreamInfo) { |
3181 | /* Init local variables */ |
3182 | UINT32 i = 0; |
3183 | /* Look through all streams */ |
3184 | for (i = 0; i < pInt->ulNumStreams; i++) { |
3185 | if (pInt->pStreamInfo[i].keyFramePacket.bValid) { |
3186 | bRet = TRUE; |
3187 | break; |
3188 | } |
3189 | } |
3190 | } |
3191 | |
3192 | return bRet; |
3193 | } |
3194 | |
3195 | HX_RESULT rm_parseri_find_first_packet_after_seek_time(rm_parser_internal* pInt, |
3196 | UINT32 ulSeekTime, |
3197 | UINT32 ulInitialOffset) |
3198 | { |
3199 | HX_RESULT retVal = HXR_FAIL; |
3200 | |
3201 | if (pInt) { |
3202 | UINT32 ulStreamNum = 0; |
3203 | UINT32 ulOffset = 0; |
3204 | struct rm_pkt_hdr hdr; |
3205 | /* Clear the return value */ |
3206 | retVal = HXR_OK; |
3207 | /* Seek to the initial offset */ |
3208 | rm_parseri_file_seek(pInt, ulInitialOffset, HX_SEEK_ORIGIN_SET); |
3209 | /* |
3210 | * Read packet headers until we find one |
3211 | * which is greater than or equal to the seek time. |
3212 | */ |
3213 | while (HX_SUCCEEDED(retVal)) { |
3214 | /* Read the next packet header */ |
3215 | retVal = rm_parseri_read_next_packet_header(pInt, &hdr); |
3216 | if (HX_SUCCEEDED(retVal)) { |
3217 | /* Compute the offset of this packet */ |
3218 | ulOffset = pInt->ulCurFileOffset - hdr.header_len; |
3219 | /* |
3220 | * Is the timestamp of this packet greater |
3221 | * than or equal to the seek time? |
3222 | */ |
3223 | if (hdr.timestamp >= ulSeekTime) { |
3224 | /* We're finished. */ |
3225 | retVal = rm_parseri_find_first_keyframe(pInt); |
3226 | break; |
3227 | } else { |
3228 | /* Assume the worst */ |
3229 | retVal = HXR_FAIL; |
3230 | /* Get the stream num */ |
3231 | ulStreamNum = rm_parseri_translate_stream_number(pInt, hdr.stream_num); |
3232 | if (ulStreamNum != RM_NO_STREAM_SET) { |
3233 | /* Get the rm_keyframe_packet struct for this stream */ |
3234 | struct rm_keyframe_packet* pKey = &pInt->pStreamInfo[ulStreamNum].keyFramePacket; |
3235 | if (pKey) { |
3236 | if (hdr.flags & HX_KEYFRAME_FLAG) { |
3237 | if (!pKey->bValid || hdr.timestamp > pKey->ulTimestamp) { |
3238 | /* Save the keyframe info */ |
3239 | pKey->ulTimestamp = hdr.timestamp; |
3240 | pKey->ulFileOffset = ulOffset; |
3241 | pKey->bValid = TRUE; |
3242 | /* Update the on-the-fly index table */ |
3243 | rm_parseri_update_seek_table(pInt, |
3244 | ulStreamNum, |
3245 | hdr.timestamp, |
3246 | ulOffset, |
3247 | hdr.flags); |
3248 | } |
3249 | } else { |
3250 | rm_parseri_update_time_range(pInt, |
3251 | ulStreamNum, |
3252 | hdr.timestamp); |
3253 | } |
3254 | /* Clear the return value */ |
3255 | retVal = HXR_OK; |
3256 | } |
3257 | } |
3258 | } |
3259 | /* |
3260 | * If we've succeeded and we're not done, |
3261 | * then seek to the next packet header. |
3262 | */ |
3263 | if (HX_SUCCEEDED(retVal)) { |
3264 | rm_parseri_file_seek(pInt, |
3265 | hdr.length - hdr.header_len, |
3266 | HX_SEEK_ORIGIN_CUR); |
3267 | } |
3268 | } |
3269 | } |
3270 | } |
3271 | |
3272 | return retVal; |
3273 | } |
3274 | |
3275 | HX_RESULT rm_parseri_find_first_keyframe(rm_parser_internal* pInt) |
3276 | { |
3277 | HX_RESULT retVal = HXR_FAIL; |
3278 | |
3279 | if (pInt && pInt->pStreamInfo && pInt->ulNumStreams) { |
3280 | UINT32 ulLowOffset = 0; |
3281 | UINT32 ulLowStream = 0; |
3282 | UINT32 ulNumValid = 0; |
3283 | UINT32 i = 0; |
3284 | /* |
3285 | * Mark the number of keyframes needed as |
3286 | * the number of streams. |
3287 | */ |
3288 | pInt->ulKeyframesNeeded = pInt->ulNumStreams; |
3289 | for (i = 0; i < pInt->ulNumStreams; i++) { |
3290 | pInt->pStreamInfo[i].bNeedKeyframe = TRUE; |
3291 | } |
3292 | /* Find the lowest offset of the valid keyframes */ |
3293 | for (i = 0; i < pInt->ulNumStreams; i++) { |
3294 | if (pInt->pStreamInfo[i].bNeedKeyframe && |
3295 | pInt->pStreamInfo[i].keyFramePacket.bValid) { |
3296 | /* Increment the number of valid keyframes */ |
3297 | ulNumValid++; |
3298 | /* Find the lowest keyframe time and stream */ |
3299 | if (!ulLowOffset || |
3300 | pInt->pStreamInfo[i].keyFramePacket.ulFileOffset < ulLowOffset) { |
3301 | ulLowOffset = pInt->pStreamInfo[i].keyFramePacket.ulFileOffset; |
3302 | ulLowStream = i; |
3303 | } |
3304 | } |
3305 | } |
3306 | /* Did we find any valid keyframes? */ |
3307 | if (ulNumValid) { |
3308 | /* Seek to the lowest offset */ |
3309 | rm_parseri_file_seek(pInt, ulLowOffset, HX_SEEK_ORIGIN_SET); |
3310 | /* Clear the return value */ |
3311 | retVal = HXR_OK; |
3312 | } else { |
3313 | /* Clear the number of keyframes needed */ |
3314 | pInt->ulKeyframesNeeded = 0; |
3315 | } |
3316 | } |
3317 | |
3318 | return retVal; |
3319 | } |
3320 | |
3321 | void* rm_parseri_malloc(rm_parser_internal* pInt, UINT32 ulSize) |
3322 | { |
3323 | void* pRet = HXNULL; |
3324 | if (pInt && pInt->fpMalloc) { |
3325 | pRet = pInt->fpMalloc(pInt->pUserMem, ulSize); |
3326 | } |
3327 | return pRet; |
3328 | } |
3329 | |
3330 | void rm_parseri_free(rm_parser_internal* pInt, void* pMem) |
3331 | { |
3332 | if (pInt && pInt->fpFree) { |
3333 | pInt->fpFree(pInt->pUserMem, pMem); |
3334 | } |
3335 | } |
3336 | |
3337 | void rm_parseri_error(rm_parser_internal* pInt, HX_RESULT err, const char* pszMsg) |
3338 | { |
3339 | if (pInt && pInt->fpError) { |
3340 | pInt->fpError(pInt->pUserError, err, pszMsg); |
3341 | } |
3342 | } |
3343 |