summaryrefslogtreecommitdiff
path: root/audio_codec/libraac/rm_parser_internal.c (plain)
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
65static 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
98HX_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
120HX_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
154HX_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
186HX_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
236void 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
262HX_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
307void 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
329void 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
347HX_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
375void 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
392void 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
410HX_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
469UINT32 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
486HXBOOL 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
505void 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
517HX_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
604void 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
628void 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
645HX_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
681void 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
691UINT32 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
709HXBOOL 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
725HXBOOL 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
738HX_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
799HX_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
822HX_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
907HX_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
943HX_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
1021HX_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
1227UINT32 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
1262HX_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
1322HXBOOL 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
1333HX_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
1390void 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
1411void 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
1420void 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
1431void 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
1445HX_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
1552HX_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
1646HX_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
1669HX_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
1702HX_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
1727HX_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
1750HX_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
1770UINT32 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
1781UINT32 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
1796HX_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
1822HX_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
1885void 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
1900void 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
1935void 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
1943UINT32 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
2277char* 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
2348HX_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
2544UINT32 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
2579UINT32 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
2601void 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
2622void 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
2637HX_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
2697HX_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
2750HX_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
2771HX_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
2827HX_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
2864HX_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
2906HX_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
3009HX_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
3097HX_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
3155HXBOOL 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
3176HXBOOL 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
3195HX_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
3275HX_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
3321void* 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
3330void rm_parseri_free(rm_parser_internal* pInt, void* pMem)
3331{
3332 if (pInt && pInt->fpFree) {
3333 pInt->fpFree(pInt->pUserMem, pMem);
3334 }
3335}
3336
3337void 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