MythTV  0.26-pre
mpls_parse.c
Go to the documentation of this file.
00001 /*
00002  * This file is part of libbluray
00003  * Copyright (C) 2009-2010  John Stebbins
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library. If not, see
00017  * <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "util/macro.h"
00021 #include "file/file.h"
00022 #include "util/bits.h"
00023 #include "mpls_parse.h"
00024 
00025 #include <stdlib.h>
00026 #include <string.h>
00027 
00028 #define MPLS_SIG1  ('M' << 24 | 'P' << 16 | 'L' << 8 | 'S')
00029 #define MPLS_SIG2A ('0' << 24 | '2' << 16 | '0' << 8 | '0')
00030 #define MPLS_SIG2B ('0' << 24 | '1' << 16 | '0' << 8 | '0')
00031 
00032 static int mpls_verbose = 0;
00033 
00034 static void
00035 _human_readable_sig(char *sig, uint32_t s1, uint32_t s2)
00036 {
00037     sig[0] = (s1 >> 24) & 0xFF;
00038     sig[1] = (s1 >> 16) & 0xFF;
00039     sig[2] = (s1 >>  8) & 0xFF;
00040     sig[3] = (s1      ) & 0xFF;
00041     sig[4] = (s2 >> 24) & 0xFF;
00042     sig[5] = (s2 >> 16) & 0xFF;
00043     sig[6] = (s2 >>  8) & 0xFF;
00044     sig[7] = (s2      ) & 0xFF;
00045     sig[8] = 0;
00046 }
00047 
00048 int
00049 mpls_parse_uo(uint8_t *buf, BD_UO_MASK *uo)
00050 {
00051     BITBUFFER bb;
00052     bb_init(&bb, buf, 8);
00053 
00054     uo->menu_call                       = bb_read(&bb, 1);
00055     uo->title_search                    = bb_read(&bb, 1);
00056     uo->chapter_search                  = bb_read(&bb, 1);
00057     uo->time_search                     = bb_read(&bb, 1);
00058     uo->skip_to_next_point              = bb_read(&bb, 1);
00059     uo->skip_to_prev_point              = bb_read(&bb, 1);
00060     uo->play_firstplay                  = bb_read(&bb, 1);
00061     uo->stop                            = bb_read(&bb, 1);
00062     uo->pause_on                        = bb_read(&bb, 1);
00063     uo->pause_off                       = bb_read(&bb, 1);
00064     uo->still                           = bb_read(&bb, 1);
00065     uo->forward                         = bb_read(&bb, 1);
00066     uo->backward                        = bb_read(&bb, 1);
00067     uo->resume                          = bb_read(&bb, 1);
00068     uo->move_up                         = bb_read(&bb, 1);
00069     uo->move_down                       = bb_read(&bb, 1);
00070     uo->move_left                       = bb_read(&bb, 1);
00071     uo->move_right                      = bb_read(&bb, 1);
00072     uo->select                          = bb_read(&bb, 1);
00073     uo->activate                        = bb_read(&bb, 1);
00074     uo->select_and_activate             = bb_read(&bb, 1);
00075     uo->primary_audio_change            = bb_read(&bb, 1);
00076     bb_skip(&bb, 1);
00077     uo->angle_change                    = bb_read(&bb, 1);
00078     uo->popup_on                        = bb_read(&bb, 1);
00079     uo->popup_off                       = bb_read(&bb, 1);
00080     uo->pg_enable_disable               = bb_read(&bb, 1);
00081     uo->pg_change                       = bb_read(&bb, 1);
00082     uo->secondary_video_enable_disable  = bb_read(&bb, 1);
00083     uo->secondary_video_change          = bb_read(&bb, 1);
00084     uo->secondary_audio_enable_disable  = bb_read(&bb, 1);
00085     uo->secondary_audio_change          = bb_read(&bb, 1);
00086     bb_skip(&bb, 1);
00087     uo->pip_pg_change                   = bb_read(&bb, 1);
00088     bb_skip(&bb, 30);
00089     return 1;
00090 }
00091 
00092 static int
00093 _parse_uo(BITSTREAM *bits, BD_UO_MASK *uo)
00094 {
00095     uint8_t buf[8];
00096     bs_read_bytes(bits, buf, 8);
00097     return mpls_parse_uo(buf, uo);
00098 }
00099 
00100 static int
00101 _parse_appinfo(BITSTREAM *bits, MPLS_AI *ai)
00102 {
00103     int len;
00104     int pos;
00105 
00106     if (!bs_is_align(bits, 0x07)) {
00107         fprintf(stderr, "_parse_appinfo: alignment error\n");
00108     }
00109     pos = bs_pos(bits) >> 3;
00110     len = bs_read(bits, 32);
00111 
00112     // Reserved
00113     bs_skip(bits, 8);
00114     ai->playback_type = bs_read(bits, 8);
00115     if (ai->playback_type == 2 || ai->playback_type == 3) {
00116         ai->playback_count = bs_read(bits, 16);
00117     } else {
00118         // Reserved
00119         bs_skip(bits, 16);
00120     }
00121     _parse_uo(bits, &ai->uo_mask);
00122     ai->random_access_flag = bs_read(bits, 1);
00123     ai->audio_mix_flag = bs_read(bits, 1);
00124     ai->lossless_bypass_flag = bs_read(bits, 1);
00125     // Reserved
00126     bs_skip(bits, 13);
00127     bs_seek_byte(bits, pos + len);
00128     return 1;
00129 }
00130 
00131 static int
00132 _parse_header(BITSTREAM *bits, MPLS_PL *pl)
00133 {
00134     pl->type_indicator  = bs_read(bits, 32);
00135     pl->type_indicator2 = bs_read(bits, 32);
00136     if (pl->type_indicator != MPLS_SIG1 || 
00137         (pl->type_indicator2 != MPLS_SIG2A && 
00138          pl->type_indicator2 != MPLS_SIG2B)) {
00139 
00140         char sig[9];
00141         char expect[9];
00142 
00143         _human_readable_sig(sig, pl->type_indicator, pl->type_indicator2);
00144         _human_readable_sig(expect, MPLS_SIG1, MPLS_SIG2A);
00145         fprintf(stderr, "failed signature match, expected (%s) got (%s)\n", 
00146                 expect, sig);
00147         return 0;
00148     }
00149     pl->list_pos = bs_read(bits, 32);
00150     pl->mark_pos = bs_read(bits, 32);
00151     pl->ext_pos  = bs_read(bits, 32);
00152 
00153     // Skip 160 reserved bits
00154     bs_skip(bits, 160);
00155 
00156     _parse_appinfo(bits, &pl->app_info);
00157     return 1;
00158 }
00159 
00160 static int
00161 _parse_stream(BITSTREAM *bits, MPLS_STREAM *s)
00162 {
00163     int len;
00164     int pos;
00165 
00166     if (!bs_is_align(bits, 0x07)) {
00167         fprintf(stderr, "_parse_stream: Stream alignment error\n");
00168     }
00169     len = bs_read(bits, 8);
00170     pos = bs_pos(bits) >> 3;
00171 
00172     s->stream_type = bs_read(bits, 8);
00173     switch (s->stream_type) {
00174         case 1:
00175             s->pid = bs_read(bits, 16);
00176             break;
00177 
00178         case 2:
00179         case 4:
00180             s->subpath_id = bs_read(bits, 8);
00181             s->subclip_id = bs_read(bits, 8);
00182             s->pid        = bs_read(bits, 16);
00183             break;
00184 
00185         case 3:
00186             s->subpath_id = bs_read(bits, 8);
00187             s->pid        = bs_read(bits, 16);
00188             break;
00189 
00190         default:
00191             fprintf(stderr, "unrecognized stream type %02x\n", s->stream_type);
00192             break;
00193     };
00194 
00195     bs_seek_byte(bits, pos + len);
00196 
00197     len = bs_read(bits, 8);
00198     pos = bs_pos(bits) >> 3;
00199 
00200     s->lang[0] = '\0';
00201     s->coding_type = bs_read(bits, 8);
00202     switch (s->coding_type) {
00203         case 0x01:
00204         case 0x02:
00205         case 0xea:
00206         case 0x1b:
00207             s->format = bs_read(bits, 4);
00208             s->rate   = bs_read(bits, 4);
00209             break;
00210 
00211         case 0x03:
00212         case 0x04:
00213         case 0x80:
00214         case 0x81:
00215         case 0x82:
00216         case 0x83:
00217         case 0x84:
00218         case 0x85:
00219         case 0x86:
00220         case 0xa1:
00221         case 0xa2:
00222             s->format = bs_read(bits, 4);
00223             s->rate   = bs_read(bits, 4);
00224             bs_read_bytes(bits, s->lang, 3);
00225             break;
00226 
00227         case 0x90:
00228         case 0x91:
00229             bs_read_bytes(bits, s->lang, 3);
00230             break;
00231 
00232         case 0x92:
00233             s->char_code = bs_read(bits, 8);
00234             bs_read_bytes(bits, s->lang, 3);
00235             break;
00236 
00237         default:
00238             fprintf(stderr, "unrecognized coding type %02x\n", s->coding_type);
00239             break;
00240     };
00241     s->lang[3] = '\0';
00242 
00243     bs_seek_byte(bits, pos + len);
00244     return 1;
00245 }
00246 
00247 static int
00248 _parse_stn(BITSTREAM *bits, MPLS_STN *stn)
00249 {
00250     int len;
00251     int pos;
00252     MPLS_STREAM    *ss;
00253     int ii,jj;
00254 
00255     if (!bs_is_align(bits, 0x07)) {
00256         fprintf(stderr, "_parse_stream: Stream alignment error\n");
00257     }
00258     // Skip STN len
00259     len = bs_read(bits, 16);
00260     pos = bs_pos(bits) >> 3;
00261 
00262     // Skip 2 reserved bytes
00263     bs_skip(bits, 16);
00264 
00265     stn->num_video           = bs_read(bits, 8);
00266     stn->num_audio           = bs_read(bits, 8);
00267     stn->num_pg              = bs_read(bits, 8);
00268     stn->num_ig              = bs_read(bits, 8);
00269     stn->num_secondary_audio = bs_read(bits, 8);
00270     stn->num_secondary_video = bs_read(bits, 8);
00271     stn->num_pip_pg          = bs_read(bits, 8);
00272 
00273     // 5 reserve bytes
00274     bs_skip(bits, 5 * 8);
00275 
00276     // Primary Video Streams
00277     ss = NULL;
00278     if (stn->num_video) {
00279         ss = calloc(stn->num_video, sizeof(MPLS_STREAM));
00280         for (ii = 0; ii < stn->num_video; ii++) {
00281             if (!_parse_stream(bits, &ss[ii])) {
00282                 X_FREE(ss);
00283                 fprintf(stderr, "error parsing video entry\n");
00284                 return 0;
00285             }
00286         }
00287     }
00288     stn->video = ss;
00289 
00290     // Primary Audio Streams
00291     ss = NULL;
00292     if (stn->num_audio) {
00293         ss = calloc(stn->num_audio, sizeof(MPLS_STREAM));
00294         for (ii = 0; ii < stn->num_audio; ii++) {
00295 
00296             if (!_parse_stream(bits, &ss[ii])) {
00297                 X_FREE(ss);
00298                 fprintf(stderr, "error parsing audio entry\n");
00299                 return 0;
00300             }
00301         }
00302     }
00303     stn->audio = ss;
00304 
00305     // Presentation Graphic Streams
00306     ss = NULL;
00307     if (stn->num_pg  || stn->num_pip_pg) {
00308         ss = calloc(stn->num_pg + stn->num_pip_pg, sizeof(MPLS_STREAM));
00309         for (ii = 0; ii < (stn->num_pg + stn->num_pip_pg); ii++) {
00310             if (!_parse_stream(bits, &ss[ii])) {
00311                 X_FREE(ss);
00312                 fprintf(stderr, "error parsing pg/pip-pg entry\n");
00313                 return 0;
00314             }
00315         }
00316     }
00317     stn->pg = ss;
00318 
00319     // Interactive Graphic Streams
00320     ss = NULL;
00321     if (stn->num_ig) {
00322         ss = calloc(stn->num_ig, sizeof(MPLS_STREAM));
00323         for (ii = 0; ii < stn->num_ig; ii++) {
00324             if (!_parse_stream(bits, &ss[ii])) {
00325                 X_FREE(ss);
00326                 fprintf(stderr, "error parsing ig entry\n");
00327                 return 0;
00328             }
00329         }
00330     }
00331     stn->ig = ss;
00332 
00333     // Secondary Audio Streams
00334     ss = NULL;
00335     if (stn->num_secondary_audio) {
00336         ss = calloc(stn->num_secondary_audio, sizeof(MPLS_STREAM));
00337         for (ii = 0; ii < stn->num_secondary_audio; ii++) {
00338             if (!_parse_stream(bits, &ss[ii])) {
00339                 X_FREE(ss);
00340                 fprintf(stderr, "error parsing secondary audio entry\n");
00341                 return 0;
00342             }
00343             // Read Secondary Audio Extra Attributes
00344             ss->sa_num_primary_audio_ref = bs_read(bits, 8);
00345             bs_skip(bits, 8);
00346             if (ss->sa_num_primary_audio_ref) {
00347                 ss->sa_primary_audio_ref = calloc(ss->sa_num_primary_audio_ref, sizeof(uint8_t));
00348                 for (jj = 0; jj < ss->sa_num_primary_audio_ref; jj++) {
00349                    ss->sa_primary_audio_ref[jj] = bs_read(bits, 8);
00350                 }
00351                 if (ss->sa_num_primary_audio_ref % 2) {
00352                     bs_skip(bits, 8);
00353                 }
00354             }
00355         }
00356     }
00357     stn->secondary_audio = ss;
00358 
00359     // Secondary Video Streams
00360     ss = NULL;
00361     if (stn->num_secondary_video) {
00362         ss = calloc(stn->num_secondary_video, sizeof(MPLS_STREAM));
00363         for (ii = 0; ii < stn->num_secondary_video; ii++) {
00364             if (!_parse_stream(bits, &ss[ii])) {
00365                 X_FREE(ss);
00366                 fprintf(stderr, "error parsing secondary video entry\n");
00367                 return 0;
00368             }
00369             // Read Secondary Video Extra Attributes
00370             ss->sv_num_secondary_audio_ref = bs_read(bits, 8);
00371            bs_skip(bits, 8);
00372             if (ss->sv_num_secondary_audio_ref) {
00373                 ss->sv_secondary_audio_ref = calloc(ss->sv_num_secondary_audio_ref, sizeof(uint8_t));
00374                 for (jj = 0; jj < ss->sv_num_secondary_audio_ref; jj++) {
00375                     ss->sv_secondary_audio_ref[jj] = bs_read(bits, 8);
00376                 }
00377                 if (ss->sv_num_secondary_audio_ref % 2) {
00378                     bs_skip(bits, 8);
00379                 }
00380             }
00381             ss->sv_num_pip_pg_ref = bs_read(bits, 8);
00382             bs_skip(bits, 8);
00383             if (ss->sv_num_pip_pg_ref) {
00384                 ss->sv_pip_pg_ref = calloc(ss->sv_num_pip_pg_ref, sizeof(uint8_t));
00385                 for (jj = 0; jj < ss->sv_num_pip_pg_ref; jj++) {
00386                     ss->sv_pip_pg_ref[jj] = bs_read(bits, 8);
00387                 }
00388                 if (ss->sv_num_pip_pg_ref % 2) {
00389                     bs_skip(bits, 8);
00390                 }
00391             }
00392 
00393         }
00394     }
00395     stn->secondary_video = ss;
00396 
00397     bs_seek_byte(bits, pos + len);
00398     return 1;
00399 }
00400 
00401 static void
00402 _clean_stn(MPLS_STN *stn)
00403 {
00404     X_FREE(stn->video);
00405     X_FREE(stn->audio);
00406     X_FREE(stn->pg);
00407     X_FREE(stn->ig);
00408     X_FREE(stn->secondary_audio);
00409     X_FREE(stn->secondary_video);
00410 }
00411 
00412 static int
00413 _parse_playitem(BITSTREAM *bits, MPLS_PI *pi)
00414 {
00415     int len, ii;
00416     int pos;
00417     char clip_id[6], codec_id[5];
00418     uint8_t stc_id;
00419 
00420     if (!bs_is_align(bits, 0x07)) {
00421         fprintf(stderr, "_parse_playitem: Stream alignment error\n");
00422     }
00423 
00424     // PlayItem Length
00425     len = bs_read(bits, 16);
00426     pos = bs_pos(bits) >> 3;
00427 
00428     // Primary Clip identifer
00429     bs_read_bytes(bits, (uint8_t*)clip_id, 5);
00430     clip_id[5] = '\0';
00431 
00432     bs_read_bytes(bits, (uint8_t*)codec_id, 4);
00433     codec_id[4] = '\0';
00434     if (memcmp(codec_id, "M2TS", 4) != 0) {
00435         fprintf(stderr, "Incorrect CodecIdentifier (%s)\n", codec_id);
00436     }
00437 
00438     // Skip reserved 11 bits
00439     bs_skip(bits, 11);
00440 
00441     pi->is_multi_angle = bs_read(bits, 1);
00442 
00443     pi->connection_condition = bs_read(bits, 4);
00444     if (pi->connection_condition != 0x01 && 
00445         pi->connection_condition != 0x05 &&
00446         pi->connection_condition != 0x06) {
00447 
00448         fprintf(stderr, "Unexpected connection condition %02x\n", 
00449                 pi->connection_condition);
00450     }
00451 
00452     stc_id   = bs_read(bits, 8);
00453     pi->in_time  = bs_read(bits, 32);
00454     pi->out_time = bs_read(bits, 32);
00455 
00456     _parse_uo(bits, &pi->uo_mask);
00457     pi->random_access_flag = bs_read(bits, 1);
00458     bs_skip(bits, 7);
00459     pi->still_mode = bs_read(bits, 8);
00460     if (pi->still_mode == 0x01) {
00461         pi->still_time = bs_read(bits, 16);
00462     } else {
00463         bs_skip(bits, 16);
00464     }
00465 
00466     pi->angle_count = 1;
00467     if (pi->is_multi_angle) {
00468         pi->angle_count = bs_read(bits, 8);
00469         if (pi->angle_count < 1) {
00470             pi->angle_count = 1;
00471         }
00472         bs_skip(bits, 6);
00473         pi->is_different_audio = bs_read(bits, 1);
00474         pi->is_seamless_angle = bs_read(bits, 1);
00475     }
00476     pi->clip = calloc(pi->angle_count, sizeof(MPLS_CLIP));
00477     strcpy(pi->clip[0].clip_id, clip_id);
00478     strcpy(pi->clip[0].codec_id, codec_id);
00479     pi->clip[0].stc_id = stc_id;
00480     for (ii = 1; ii < pi->angle_count; ii++) {
00481         bs_read_bytes(bits, (uint8_t*)pi->clip[ii].clip_id, 5);
00482         pi->clip[ii].clip_id[5] = '\0';
00483 
00484         bs_read_bytes(bits, (uint8_t*)pi->clip[ii].codec_id, 4);
00485         pi->clip[ii].codec_id[4] = '\0';
00486         if (memcmp(pi->clip[ii].codec_id, "M2TS", 4) != 0) {
00487             fprintf(stderr, "Incorrect CodecIdentifier (%s)\n", pi->clip[ii].codec_id);
00488         }
00489         pi->clip[ii].stc_id   = bs_read(bits, 8);
00490     }
00491     if (!_parse_stn(bits, &pi->stn)) {
00492         return 0;
00493     }
00494     // Seek past any unused items
00495     bs_seek_byte(bits, pos + len);
00496     return 1;
00497 }
00498 
00499 static void
00500 _clean_playitem(MPLS_PI *pi)
00501 {
00502     X_FREE(pi->clip);
00503     _clean_stn(&pi->stn);
00504 }
00505 
00506 static int
00507 _parse_subplayitem(BITSTREAM *bits, MPLS_SUB_PI *spi)
00508 {
00509     int len, ii;
00510     int pos;
00511     char clip_id[6], codec_id[5];
00512     uint8_t stc_id;
00513 
00514     if (!bs_is_align(bits, 0x07)) {
00515         fprintf(stderr, "_parse_subplayitem: alignment error\n");
00516     }
00517 
00518     // PlayItem Length
00519     len = bs_read(bits, 16);
00520     pos = bs_pos(bits) >> 3;
00521 
00522     // Primary Clip identifer
00523     bs_read_bytes(bits, (uint8_t*)clip_id, 5);
00524     clip_id[5] = '\0';
00525 
00526     bs_read_bytes(bits, (uint8_t*)codec_id, 4);
00527     codec_id[4] = '\0';
00528     if (memcmp(codec_id, "M2TS", 4) != 0) {
00529         fprintf(stderr, "Incorrect CodecIdentifier (%s)\n", codec_id);
00530     }
00531 
00532     bs_skip(bits, 27);
00533 
00534     spi->connection_condition = bs_read(bits, 4);
00535 
00536     if (spi->connection_condition != 0x01 && 
00537         spi->connection_condition != 0x05 &&
00538         spi->connection_condition != 0x06) {
00539 
00540         fprintf(stderr, "Unexpected connection condition %02x\n", 
00541                 spi->connection_condition);
00542     }
00543     spi->is_multi_clip     = bs_read(bits, 1);
00544     stc_id                 = bs_read(bits, 8);
00545     spi->in_time           = bs_read(bits, 32);
00546     spi->out_time          = bs_read(bits, 32);
00547     spi->sync_play_item_id = bs_read(bits, 16);
00548     spi->sync_pts          = bs_read(bits, 32);
00549     spi->clip_count = 1;
00550     if (spi->is_multi_clip) {
00551         spi->clip_count    = bs_read(bits, 8);
00552         if (spi->clip_count < 1) {
00553             spi->clip_count = 1;
00554         }
00555     }
00556     spi->clip = calloc(spi->clip_count, sizeof(MPLS_CLIP));
00557     strcpy(spi->clip[0].clip_id, clip_id);
00558     strcpy(spi->clip[0].codec_id, codec_id);
00559     spi->clip[0].stc_id = stc_id;
00560     for (ii = 1; ii < spi->clip_count; ii++) {
00561         // Primary Clip identifer
00562         bs_read_bytes(bits, (uint8_t*)spi->clip[ii].clip_id, 5);
00563         spi->clip[ii].clip_id[5] = '\0';
00564 
00565         bs_read_bytes(bits, (uint8_t*)spi->clip[ii].codec_id, 4);
00566         spi->clip[ii].codec_id[4] = '\0';
00567         if (memcmp(spi->clip[ii].codec_id, "M2TS", 4) != 0) {
00568             fprintf(stderr, "Incorrect CodecIdentifier (%s)\n", spi->clip[ii].codec_id);
00569         }
00570         spi->clip[ii].stc_id = bs_read(bits, 8);
00571     }
00572 
00573 
00574     // Seek to end of subpath
00575     bs_seek_byte(bits, pos + len);
00576     return 1;
00577 }
00578 
00579 static void
00580 _clean_subplayitem(MPLS_SUB_PI *spi)
00581 {
00582     X_FREE(spi->clip);
00583 }
00584 
00585 static int
00586 _parse_subpath(BITSTREAM *bits, MPLS_SUB *sp)
00587 {
00588     int len, ii;
00589     int pos;
00590     MPLS_SUB_PI *spi = NULL;
00591 
00592     if (!bs_is_align(bits, 0x07)) {
00593         fprintf(stderr, "_parse_subpath: alignment error\n");
00594     }
00595 
00596     // PlayItem Length
00597     len = bs_read(bits, 32);
00598     pos = bs_pos(bits) >> 3;
00599 
00600     bs_skip(bits, 8);
00601     sp->type = bs_read(bits, 8);
00602     bs_skip(bits, 15);
00603     sp->is_repeat = bs_read(bits, 1);
00604     bs_skip(bits, 8);
00605     sp->sub_playitem_count = bs_read(bits, 8);
00606 
00607     spi = calloc(sp->sub_playitem_count,  sizeof(MPLS_SUB_PI));
00608     for (ii = 0; ii < sp->sub_playitem_count; ii++) {
00609         if (!_parse_subplayitem(bits, &spi[ii])) {
00610             X_FREE(spi);
00611             fprintf(stderr, "error parsing sub play item\n");
00612             return 0;
00613         }
00614     }
00615     sp->sub_play_item = spi;
00616 
00617     // Seek to end of subpath
00618     bs_seek_byte(bits, pos + len);
00619     return 1;
00620 }
00621 
00622 static void
00623 _clean_subpath(MPLS_SUB *sp)
00624 {
00625     int ii;
00626 
00627     for (ii = 0; ii < sp->sub_playitem_count; ii++) {
00628         _clean_subplayitem(&sp->sub_play_item[ii]);
00629     }
00630     X_FREE(sp->sub_play_item);
00631 }
00632 
00633 static int
00634 _parse_playlistmark(BITSTREAM *bits, MPLS_PL *pl)
00635 {
00636     int ii;
00637     MPLS_PLM *plm = NULL;
00638 
00639     bs_seek_byte(bits, pl->mark_pos);
00640     // Skip the length field, I don't use it
00641     bs_skip(bits, 32);
00642     // Then get the number of marks
00643     pl->mark_count = bs_read(bits, 16);
00644 
00645     plm = calloc(pl->mark_count, sizeof(MPLS_PLM));
00646     for (ii = 0; ii < pl->mark_count; ii++) {
00647         plm[ii].mark_id       = bs_read(bits, 8);
00648         plm[ii].mark_type     = bs_read(bits, 8);
00649         plm[ii].play_item_ref = bs_read(bits, 16);
00650         plm[ii].time          = bs_read(bits, 32);
00651         plm[ii].entry_es_pid  = bs_read(bits, 16);
00652         plm[ii].duration      = bs_read(bits, 32);
00653     }
00654     pl->play_mark = plm;
00655     return 1;
00656 }
00657 
00658 static int
00659 _parse_playlist(BITSTREAM *bits, MPLS_PL *pl)
00660 {
00661     int ii;
00662     MPLS_PI *pi = NULL;
00663     MPLS_SUB *sub_path = NULL;
00664 
00665     bs_seek_byte(bits, pl->list_pos);
00666     // Skip playlist length
00667     bs_skip(bits, 32);
00668     // Skip reserved bytes
00669     bs_skip(bits, 16);
00670 
00671     pl->list_count = bs_read(bits, 16);
00672     pl->sub_count = bs_read(bits, 16);
00673 
00674     pi = calloc(pl->list_count,  sizeof(MPLS_PI));
00675     for (ii = 0; ii < pl->list_count; ii++) {
00676         if (!_parse_playitem(bits, &pi[ii])) {
00677             X_FREE(pi);
00678             fprintf(stderr, "error parsing play list item\n");
00679             return 0;
00680         }
00681     }
00682     pl->play_item = pi;
00683 
00684     sub_path = calloc(pl->sub_count,  sizeof(MPLS_SUB));
00685     for (ii = 0; ii < pl->sub_count; ii++)
00686     {
00687         if (!_parse_subpath(bits, &sub_path[ii]))
00688         {
00689             X_FREE(sub_path);
00690             fprintf(stderr, "error parsing subpath\n");
00691             return 0;
00692         }
00693     }
00694     pl->sub_path = sub_path;
00695 
00696     return 1;
00697 }
00698 
00699 static void
00700 _clean_playlist(MPLS_PL *pl)
00701 {
00702     int ii;
00703 
00704     if (pl == NULL) {
00705         return;
00706     }
00707     if (pl->play_item != NULL) {
00708         for (ii = 0; ii < pl->list_count; ii++) {
00709             _clean_playitem(&pl->play_item[ii]);
00710         }
00711         X_FREE(pl->play_item);
00712     }
00713     if (pl->sub_path != NULL) {
00714         for (ii = 0; ii < pl->sub_count; ii++) {
00715             _clean_subpath(&pl->sub_path[ii]);
00716         }
00717         X_FREE(pl->sub_path);
00718     }
00719     X_FREE(pl->play_mark);
00720     X_FREE(pl);
00721 }
00722 
00723 void
00724 mpls_free(MPLS_PL *pl)
00725 {
00726     _clean_playlist(pl);
00727 }
00728 
00729 MPLS_PL*
00730 mpls_parse(char *path, int verbose)
00731 {
00732     BITSTREAM  bits;
00733     BD_FILE_H *fp;
00734     MPLS_PL   *pl = NULL;
00735 
00736     mpls_verbose = verbose;
00737 
00738     pl = calloc(1, sizeof(MPLS_PL));
00739     if (pl == NULL) {
00740         return NULL;
00741     }
00742 
00743     fp = file_open(path, "rb");
00744     if (fp == NULL) {
00745         fprintf(stderr, "Failed to open %s\n", path);
00746         X_FREE(pl);
00747         return NULL;
00748     }
00749 
00750     bs_init(&bits, fp);
00751     if (!_parse_header(&bits, pl)) {
00752         file_close(fp);
00753         _clean_playlist(pl);
00754         return NULL;
00755     }
00756     if (!_parse_playlist(&bits, pl)) {
00757         file_close(fp);
00758         _clean_playlist(pl);
00759         return NULL;
00760     }
00761     if (!_parse_playlistmark(&bits, pl)) {
00762         file_close(fp);
00763         _clean_playlist(pl);
00764         return NULL;
00765     }
00766     file_close(fp);
00767     return pl;
00768 }
00769 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends