Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / bdwrite.C
1 //#include "bd.h"
2 //This program was created by inverting libbluray, without any docs,
3 //  so it is probably got problems.  Still, works on my Samsung player.
4 //  thanks to: Petri Hintukainen, William Hahne, John Stebbinsm, et.al.
5 //
6 //Usage:
7 // ./bd <tgt_dir_path> <playlist-0> <sep> <playlistp1> <sep> ... <sep> <playlist-n>
8 //    <sep> == -<pgm_pid> | --<pgm_pid> | ---<pgm_pid>
9 //    <pgm_pid> may be empty string, or a numeric pgm_pid for curr title clip
10 //    <pgm_pid> defaults to first pgm probed.
11 //    <playlist-x> == <clip-0.m2ts> <clip-1.m2ts> ... <clip-n.m2ts>
12 // eg:
13 // ./brwrite /tmp/dir /path/menu.m2ts --- /path/clip0.m2ts /path/clip1.m2ts -- /path/clip2.m2ts
14 //
15 // one title is built for each playlist
16 // playlist-0 is used as first-play item
17 //
18 // the basic idea is to use playlist-0 as a menu / directions to
19 // use the bluray player remote-control to select the desired title
20 // and start the play, avoiding the need for a menu system.
21 //
22 // if the first play item is the main title, that is ok also.
23 // ./brwrite /tmp/dir /path/title.m2ts
24 //
25 //
26 //To use a bluray bd-re rewriteable: (such as for /dev/sr1)
27 // dvd+rw-format /dev/sr1  (only done once to init the media)
28 // mkudffs /dev/sr1 $((`cat /sys/block/sr1/size`*512/2048-1))
29 // mount /dev/sr1 /mnt1
30 // cp -av <tgd_dir_path>/BDMV /mnt1/.
31 // umount /mnt1
32 // eject sr1
33 //
34 #ifndef __BD_H__
35 #define __BD_H__
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <endian.h>
42 #include <limits.h>
43 #include <sys/stat.h>
44 // work arounds (centos)
45 #ifndef INT64_MAX
46 #define INT64_MAX 9223372036854775807LL
47 #endif
48 #ifndef INT64_MIN
49 #define INT64_MIN (-INT64_MAX-1)
50 #endif
51
52 #include "arraylist.h"
53 #include "cstrdup.h"
54 #define BCTEXTLEN 1024
55 #define BLURAY_TS_PKTSZ 192L
56
57
58 extern "C" {
59 #include "libavfilter/buffersrc.h"
60 #include "libavfilter/buffersink.h"
61 #include "libavformat/avformat.h"
62 #include "libavformat/avio.h"
63 #include "libavcodec/avcodec.h"
64 #include "libavfilter/avfilter.h"
65 #include "libavutil/avutil.h"
66 #include "libavutil/opt.h"
67 #include "libavutil/pixdesc.h"
68 #include "libswresample/swresample.h"
69 #include "libswscale/swscale.h"
70 }
71
72 class stream;
73
74 enum {
75   obj_hdmv = 1,
76   obj_bdj = 2,
77   title_len = 20,
78   pb_typ_movie = 0,
79   pb_typ_iactv = 1,
80   pb_len = 16,
81
82   BLURAY_APP_TYPE_MAIN_MOVIE = 1,
83   BLURAY_APP_TYPE_MAIN_TIMED_SLIDE_SHOW = 2,
84   BLURAY_APP_TYPE_MAIN_BROWSED_SLIDE_SHOW = 3,
85   BLURAY_APP_TYPE_SUBPATH_BROWSED_SLIDE_SHOW = 4,
86   BLURAY_APP_TYPE_SUBPATH_IG_MENU = 5,
87   BLURAY_APP_TYPE_SUBPATH_TEXT_SUBTITLE = 6,
88   BLURAY_APP_TYPE_SUBPATH_ELEMENTARY_STREAM = 7,
89
90   BLURAY_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
91   BLURAY_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
92   BLURAY_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
93   BLURAY_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
94   BLURAY_STREAM_TYPE_AUDIO_LPCM = 0x80,
95   BLURAY_STREAM_TYPE_AUDIO_AC3 = 0x81,
96   BLURAY_STREAM_TYPE_AUDIO_DTS = 0x82,
97   BLURAY_STREAM_TYPE_AUDIO_TRUHD = 0x83,
98   BLURAY_STREAM_TYPE_AUDIO_AC3PLUS = 0x84,
99   BLURAY_STREAM_TYPE_AUDIO_DTSHD = 0x85,
100   BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER = 0x86,
101   BLURAY_STREAM_TYPE_VIDEO_VC1 = 0xea,
102   BLURAY_STREAM_TYPE_VIDEO_H264 = 0x1b,
103   BLURAY_STREAM_TYPE_VIDEO_H264_MVC = 0x20,
104   BLURAY_STREAM_TYPE_SUB_PG = 0x90,
105   BLURAY_STREAM_TYPE_SUB_IG = 0x91,
106   BLURAY_STREAM_TYPE_SUB_TEXT = 0x92,
107   BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY = 0xa1,
108   BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY = 0xa2,
109
110   BLURAY_MARK_TYPE_ENTRY = 0x01,
111   BLURAY_MARK_TYPE_LINK  = 0x02,
112
113   BLURAY_PLAYBACK_TYPE_SEQUENTIAL = 1,
114   BLURAY_PLAYBACK_TYPE_RANDOM = 2,
115   BLURAY_PLAYBACK_TYPE_SHUFFLE = 3,
116
117   BLURAY_VIDEO_FORMAT_480I = 1,  // ITU-R BT.601-5
118   BLURAY_VIDEO_FORMAT_576I = 2,  // ITU-R BT.601-4
119   BLURAY_VIDEO_FORMAT_480P = 3,  // SMPTE 293M
120   BLURAY_VIDEO_FORMAT_1080I = 4, // SMPTE 274M
121   BLURAY_VIDEO_FORMAT_720P = 5,  // SMPTE 296M
122   BLURAY_VIDEO_FORMAT_1080P = 6, // SMPTE 274M
123   BLURAY_VIDEO_FORMAT_576P = 7,  // ITU-R BT.1358
124
125   BLURAY_VIDEO_RATE_24000_1001 = 1, // 23.976
126   BLURAY_VIDEO_RATE_24 = 2,
127   BLURAY_VIDEO_RATE_25 = 3,
128   BLURAY_VIDEO_RATE_30000_1001 = 4, // 29.97
129   BLURAY_VIDEO_RATE_50 = 6,
130   BLURAY_VIDEO_RATE_60000_1001 = 7, // 59.94
131
132   BLURAY_ASPECT_RATIO_4_3 = 2,
133   BLURAY_ASPECT_RATIO_16_9 = 3,
134
135   BLURAY_AUDIO_FORMAT_MONO = 1,
136   BLURAY_AUDIO_FORMAT_STEREO = 3,
137   BLURAY_AUDIO_FORMAT_MULTI_CHAN = 6,
138   BLURAY_AUDIO_FORMAT_COMBO = 12,   // Stereo ac3/dts, 
139
140   BLURAY_AUDIO_RATE_48 = 1,
141   BLURAY_AUDIO_RATE_96 = 4,
142   BLURAY_AUDIO_RATE_192 = 5,
143   BLURAY_AUDIO_RATE_192_COMBO = 12, // 48 or 96 ac3/dts, 192 mpl/dts-hd
144   BLURAY_AUDIO_RATE_96_COMBO = 14,  // 48 ac3/dts, 96 mpl/dts-hd
145   BLURAY_TEXT_CHAR_CODE_UTF8 = 0x01,
146   BLURAY_TEXT_CHAR_CODE_UTF16BE = 0x02,
147   BLURAY_TEXT_CHAR_CODE_SHIFT_JIS = 0x03,
148   BLURAY_TEXT_CHAR_CODE_EUC_KR = 0x04,
149   BLURAY_TEXT_CHAR_CODE_GB18030_20001 = 0x05,
150   BLURAY_TEXT_CHAR_CODE_CN_GB = 0x06,
151   BLURAY_TEXT_CHAR_CODE_BIG5 = 0x07,
152
153   BLURAY_STILL_NONE = 0x00,
154   BLURAY_STILL_TIME = 0x01,
155   BLURAY_STILL_INFINITE = 0x02,
156
157   BLURAY_PG_TEXTST_STREAM = 0x01,
158   BLURAY_SECONDARY_VIDEO_STREAM = 0x02,
159   BLURAY_SECONDARY_AUDIO_STREAM = 0x03,
160 };
161
162 class bs_file {
163   FILE *fp;
164   uint32_t reg, len;
165   int64_t fpos, fsz;
166 public:
167   bs_file() { fp = 0; }
168   ~bs_file() {}
169
170   void init();
171   int  open(const char *fn);
172   void close();
173   void write(uint32_t v, int n);
174   void pad(int n);
175   void padb(int n) { pad(n*8); }
176   int64_t posb() { return fpos; }
177   void posb(int64_t n);
178   int64_t pos() { return posb()*8 + len; }
179   void writeb(uint8_t * bp, int n);
180   void writeb(const char *cp, int n) {
181     writeb((uint8_t *) cp, n);
182   }
183 };
184
185 class bs_length {
186   int64_t fpos, len;
187 public:
188   bs_length() { fpos = len = 0; }
189   void bs_len(bs_file &bs, int n) {
190     bs.write(len, n);  fpos = bs.posb();
191   }
192   void bs_end(bs_file &bs) {
193     len = bs.posb() - fpos;
194   }
195   void bs_ofs(bs_file &bs, int n) {
196     bs.write(fpos-n/8, n);
197   }
198 };
199
200 class _bd_stream_info {
201 public:
202   uint8_t coding_type;
203   uint8_t format;
204   uint8_t rate;
205   uint8_t char_code;
206   uint8_t lang[4];
207   uint16_t pid;
208   uint8_t aspect;
209   uint8_t subpath_id;
210
211   _bd_stream_info() { memset(this, 0, sizeof(*this)); }
212   ~_bd_stream_info() {}
213 };
214
215 class bd_stream_info : public _bd_stream_info {
216 public:
217   bd_stream_info() {}
218   ~bd_stream_info() {}
219 };
220
221 class _bd_clip_info {
222 public:
223   uint32_t pkt_count;
224   uint8_t still_mode;
225   uint16_t still_time;          /* seconds */
226   uint64_t start_time;
227   uint64_t in_time;
228   uint64_t out_time;
229
230   _bd_clip_info() { memset(this, 0, sizeof(*this)); }
231   ~_bd_clip_info() {}
232 };
233
234 class bd_clip_info : public _bd_clip_info {
235 public:
236   ArrayList<bd_stream_info *> video_streams;
237   ArrayList<bd_stream_info *> audio_streams;
238   ArrayList<bd_stream_info *> pg_streams;
239   ArrayList<bd_stream_info *> ig_streams;
240   ArrayList<bd_stream_info *> sec_audio_streams;
241   ArrayList<bd_stream_info *> sec_video_streams;
242
243   bd_clip_info() {}
244   ~bd_clip_info() {
245     video_streams.remove_all_objects();
246     audio_streams.remove_all_objects();
247     pg_streams.remove_all_objects();
248     ig_streams.remove_all_objects();
249     sec_audio_streams.remove_all_objects();
250     sec_video_streams.remove_all_objects();
251   }
252 };
253
254 class _bd_title_chapter {
255 public:
256   uint32_t idx;
257   uint64_t start;
258   uint64_t duration;
259   uint64_t offset;
260   unsigned clip_ref;
261
262   _bd_title_chapter() { memset(this, 0, sizeof(*this)); }
263   ~_bd_title_chapter() {}
264 };
265
266 class bd_title_chapter : public _bd_title_chapter {
267 public:
268   bd_title_chapter() {}
269   ~bd_title_chapter() {}
270 };
271
272 class _bd_title_mark {
273 public:
274   uint32_t idx;
275   int type;
276   uint64_t start;
277   uint64_t duration;
278   uint64_t offset;
279   unsigned clip_ref;
280
281   _bd_title_mark() { memset(this, 0, sizeof(*this)); }
282   ~_bd_title_mark() {}
283 };
284
285 class bd_title_mark : public _bd_title_mark {
286 public:
287   bd_title_mark() {}
288   ~bd_title_mark() {}
289 };
290
291 class _bd_title_info {
292 public:
293   uint32_t idx;
294   uint32_t playlist;
295   uint64_t duration;
296   uint8_t angle_count;
297
298   _bd_title_info() { memset(this, 0, sizeof(*this)); }
299   ~_bd_title_info() {}
300 };
301
302 class bd_title_info : public _bd_title_info {
303 public:
304   ArrayList<bd_clip_info *> clips;
305   ArrayList<bd_title_chapter *> chapters;
306   ArrayList<bd_title_mark *> marks;
307
308   bd_title_info() {}
309   ~bd_title_info() {
310     clips.remove_all_objects();
311     chapters.remove_all_objects();
312     marks.remove_all_objects();
313   }
314 };
315
316 class _clpi_stc_seq {
317 public:
318   uint16_t pcr_pid;
319   uint32_t spn_stc_start;
320   uint32_t presentation_start_time;
321   uint32_t presentation_end_time;
322
323   _clpi_stc_seq() { memset(this, 0, sizeof(*this)); }
324   ~_clpi_stc_seq() {}
325 };
326
327 class clpi_stc_seq : public _clpi_stc_seq {
328 public:
329   int write();
330
331   clpi_stc_seq() {}
332   ~clpi_stc_seq() {}
333 };
334
335 class _clpi_atc_seq {
336 public:
337   uint32_t spn_atc_start;
338   uint8_t offset_stc_id;
339
340   _clpi_atc_seq() { memset(this, 0, sizeof(*this)); }
341   ~_clpi_atc_seq() {}
342 };
343
344 class clpi_atc_seq : public _clpi_atc_seq {
345 public:
346   ArrayList<clpi_stc_seq *> stc_seq;
347   int write();
348
349   clpi_atc_seq() {}
350   ~clpi_atc_seq() {
351     stc_seq.remove_all_objects();
352   }
353 };
354
355 class clpi_sequences : public bs_length,
356                         public ArrayList<clpi_atc_seq *> {
357 public:
358   int write();
359
360   clpi_sequences() {}
361   ~clpi_sequences() { remove_all_objects(); }
362 };
363
364 class _clpi_ts_type {
365 public:
366   uint8_t validity;
367   char format_id[5];
368
369   _clpi_ts_type() { memset(this, 0, sizeof(*this)); }
370   ~_clpi_ts_type() {}
371 };
372
373 class clpi_ts_type : public _clpi_ts_type {
374 public:
375   clpi_ts_type() {}
376   ~clpi_ts_type() {}
377 };
378
379 class _clpi_atc_delta {
380 public:
381   uint32_t delta;
382   char file_id[6];
383   char file_code[5];
384
385   _clpi_atc_delta() { memset(this, 0, sizeof(*this)); }
386   ~_clpi_atc_delta() {}
387 };
388
389 class clpi_atc_delta : public _clpi_atc_delta {
390 public:
391   int write();
392
393   clpi_atc_delta() {}
394   ~clpi_atc_delta() {}
395 };
396
397 class _clpi_font {
398 public:
399   char file_id[6];
400
401   _clpi_font() { memset(this, 0, sizeof(*this)); }
402   ~_clpi_font() {}
403 };
404
405 class clpi_font : public _clpi_font {
406 public:
407   clpi_font() {}
408   ~clpi_font() {}
409 };
410
411 class clpi_font_info {
412 public:
413   ArrayList<clpi_font *> font;
414
415   clpi_font_info() {}
416   ~clpi_font_info() {
417     font.remove_all_objects();
418   }
419 };
420
421 class _clpi_clip_info {
422 public:
423   uint8_t clip_stream_type;
424   uint8_t application_type;
425   uint8_t is_atc_delta;
426   uint32_t ts_recording_rate;
427   uint32_t num_source_packets;
428
429   _clpi_clip_info() { memset(this, 0, sizeof(*this)); }
430   ~_clpi_clip_info() {}
431 };
432
433 class clpi_clip_info : public bs_length, public _clpi_clip_info {
434 public:
435   clpi_ts_type ts_type_info;
436   clpi_font_info font_info;
437   ArrayList<clpi_atc_delta *> atc_delta;
438   int write();
439
440   clpi_clip_info() {}
441   ~clpi_clip_info() {
442     atc_delta.remove_all_objects();
443   }
444 };
445
446 class _clpi_prog_stream {
447 public:
448   uint16_t pid;
449   uint8_t coding_type;
450   uint8_t format;
451   uint8_t rate;
452   uint8_t aspect;
453   uint8_t oc_flag;
454   uint8_t char_code;
455   char lang[4];
456
457   _clpi_prog_stream() { memset(this, 0, sizeof(*this)); }
458   ~_clpi_prog_stream() {}
459 };
460
461 class clpi_prog_stream : public bs_length, public _clpi_prog_stream {
462 public:
463   int write();
464
465   clpi_prog_stream() {}
466   ~clpi_prog_stream() {}
467 };
468
469 class _clpi_ep_coarse {
470 public:
471   int ref_ep_fine_id;
472   int pts_ep;
473   uint32_t spn_ep;
474
475   _clpi_ep_coarse() { memset(this, 0, sizeof(*this)); }
476   ~_clpi_ep_coarse() {}
477 };
478
479 class clpi_ep_coarse : public _clpi_ep_coarse {
480 public:
481   int write();
482
483   clpi_ep_coarse() {}
484   ~clpi_ep_coarse() {}
485 };
486
487 class _clpi_ep_fine {
488 public:
489   uint8_t is_angle_change_point;
490   uint8_t i_end_position_offset;
491   int pts_ep;
492   int spn_ep;
493
494   _clpi_ep_fine() { memset(this, 0, sizeof(*this)); }
495   ~_clpi_ep_fine() {}
496 };
497
498 class clpi_ep_fine : public _clpi_ep_fine {
499 public:
500   int write();
501
502   clpi_ep_fine() {}
503   ~clpi_ep_fine() {}
504 };
505
506 class _clpi_ep_map_entry {
507 public:
508   uint8_t ep_stream_type;
509   uint32_t ep_map_stream_start_addr;
510
511   _clpi_ep_map_entry() { memset(this, 0, sizeof(*this)); }
512   ~_clpi_ep_map_entry() {}
513 };
514
515 class clpi_ep_map_entry : public _clpi_ep_map_entry {
516 public:
517   uint32_t fine_start;
518   uint16_t pid;
519   ArrayList<clpi_ep_coarse *> coarse;
520   ArrayList<clpi_ep_fine *> fine;
521   int write(uint32_t ep_map_pos);
522   int write_map();
523
524   clpi_ep_map_entry(int id) { fine_start = 0;  pid = id; }
525   ~clpi_ep_map_entry() {
526     coarse.remove_all_objects();
527     fine.remove_all_objects();
528   }
529 };
530
531 class _clpi_prog {
532 public:
533   uint32_t spn_program_sequence_start;
534   uint8_t num_groups;
535   _clpi_prog() { memset(this, 0, sizeof(*this)); }
536   ~_clpi_prog() {}
537 };
538
539 class clpi_prog : public _clpi_prog {
540 public:
541   ArrayList<clpi_prog_stream *> streams;
542   uint16_t program_map_pid;
543
544   int write();
545   clpi_prog(int pmt_pid) { program_map_pid = pmt_pid; }
546   ~clpi_prog() { streams.remove_all_objects(); }
547 };
548
549 class clpi_programs : public bs_length,
550                         public ArrayList<clpi_prog *> {
551 public:
552   int write();
553
554   clpi_programs() {}
555   ~clpi_programs() { remove_all_objects(); }
556 };
557
558 class clpi_extents : public bs_length,
559                         public ArrayList<uint32_t> {
560 public:
561   int write();
562
563   clpi_extents() {}
564   ~clpi_extents() {}
565 };
566 class _clpi_cpi {
567 public:
568   uint8_t type;
569
570   _clpi_cpi() { type = 0; }
571   ~_clpi_cpi() {}
572 };
573
574 class clpi_cpi : public bs_length, public _clpi_cpi,
575                         public ArrayList<clpi_ep_map_entry *> {
576 public:
577   int write();
578
579   clpi_cpi() {}
580   ~clpi_cpi() { remove_all_objects(); }
581 };
582
583 class bd_uo_mask {
584 public:
585   unsigned int menu_call : 1;
586   unsigned int title_search : 1;
587   unsigned int chapter_search : 1;
588   unsigned int time_search : 1;
589   unsigned int skip_to_next_point : 1;
590   unsigned int skip_to_prev_point : 1;
591   unsigned int play_firstplay : 1;
592   unsigned int stop : 1;
593   unsigned int pause_on : 1;
594   unsigned int pause_off : 1;
595   unsigned int still_off : 1;
596   unsigned int forward : 1;
597   unsigned int backward : 1;
598   unsigned int resume : 1;
599   unsigned int move_up : 1;
600   unsigned int move_down : 1;
601   unsigned int move_left : 1;
602   unsigned int move_right : 1;
603   unsigned int select : 1;
604   unsigned int activate : 1;
605   unsigned int select_and_activate : 1;
606   unsigned int primary_audio_change : 1;
607   unsigned int reserved0 : 1;
608   unsigned int angle_change : 1;
609   unsigned int popup_on : 1;
610   unsigned int popup_off : 1;
611   unsigned int pg_enable_disable : 1;
612   unsigned int pg_change : 1;
613   unsigned int secondary_video_enable_disable : 1;
614   unsigned int secondary_video_change : 1;
615   unsigned int secondary_audio_enable_disable : 1;
616   unsigned int secondary_audio_change : 1;
617   unsigned int reserved1 : 1;
618   unsigned int pip_pg_change : 1;
619
620   int write();
621   bd_uo_mask() {
622     memset(this, 0, sizeof(*this));
623   }
624   ~bd_uo_mask() {
625   }
626 };
627
628 class _mpls_stream {
629 public:
630   uint8_t stream_type;
631   uint8_t coding_type;
632   uint16_t pid;
633   uint8_t subpath_id;
634   uint8_t subclip_id;
635   uint8_t format;
636   uint8_t rate;
637   uint8_t char_code;
638   char lang[4];
639
640   _mpls_stream() { memset(this, 0, sizeof(*this)); }
641   ~_mpls_stream() {}
642 };
643
644 class mpls_stream : public _mpls_stream {
645 public:
646   bs_length strm, code;
647   int write();
648
649   mpls_stream() {}
650   ~mpls_stream() {}
651 };
652
653 class _mpls_stn {
654 public:
655   uint8_t num_pip_pg;
656   _mpls_stn() {
657     num_pip_pg = 0;
658   }
659   ~_mpls_stn() {}
660 };
661
662 class mpls_stn : public bs_length, public _mpls_stn {
663 public:
664   ArrayList<mpls_stream *> video;
665   ArrayList<mpls_stream *> audio;
666   ArrayList<mpls_stream *> pg;
667   ArrayList<mpls_stream *> ig;
668   ArrayList<mpls_stream *> secondary_audio;
669   ArrayList<mpls_stream *> secondary_video;
670   // Secondary audio specific fields
671   ArrayList<uint8_t> sa_primary_audio_ref;
672   // Secondary video specific fields
673   ArrayList<uint8_t> sv_secondary_audio_ref;
674   ArrayList<uint8_t> sv_pip_pg_ref;
675
676   int write();
677   mpls_stn() {}
678   ~mpls_stn() {
679     video.remove_all_objects();
680     audio.remove_all_objects();
681     pg.remove_all_objects();
682     ig.remove_all_objects();
683     secondary_audio.remove_all_objects();
684     secondary_video.remove_all_objects();
685   }
686 };
687
688 class _mpls_clip {
689 public:
690   char clip_id[6];
691   char codec_id[5];
692   uint8_t stc_id;
693
694   _mpls_clip() { memset(this, 0, sizeof(*this)); }
695   ~_mpls_clip() {}
696 };
697
698 class mpls_clip : public _mpls_clip {
699 public:
700   mpls_clip() { strcpy(codec_id, "M2TS"); }
701   ~mpls_clip() {}
702 };
703
704 class _mpls_pi {
705 public:
706   uint8_t is_multi_angle;
707   uint8_t connection_condition;
708   uint32_t in_time;
709   uint32_t out_time;
710   uint8_t random_access_flag;
711   uint8_t still_mode;
712   uint16_t still_time;
713   uint8_t is_different_audio;
714   uint8_t is_seamless_angle;
715
716   _mpls_pi() { memset(this, 0, sizeof(*this)); }
717   ~_mpls_pi() {}
718 };
719
720 class mpls_pi : public bs_length, public _mpls_pi {
721 public:
722   bd_uo_mask uo_mask;
723   ArrayList<mpls_clip *> clip;
724   mpls_stn stn;
725
726   int write();
727
728   mpls_pi() {}
729   ~mpls_pi() {
730     clip.remove_all_objects();
731   }
732 };
733
734 class _mpls_plm {
735 public:
736   uint8_t mark_id;
737   uint8_t mark_type;
738   uint16_t play_item_ref;
739   uint32_t time;
740   uint16_t entry_es_pid;
741   uint32_t duration;
742
743   _mpls_plm() { memset(this, 0, sizeof(*this)); }
744   ~_mpls_plm() {}
745 };
746
747 class mpls_plm : public _mpls_plm {
748 public:
749   int write();
750
751   mpls_plm() {}
752   ~mpls_plm() {}
753 };
754
755 class _mpls_ai {
756 public:
757   uint8_t playback_type;
758   uint16_t playback_count;
759   uint8_t random_access_flag;
760   uint8_t audio_mix_flag;
761   uint8_t lossless_bypass_flag;
762
763   _mpls_ai() { memset(this, 0, sizeof(*this)); }
764   ~_mpls_ai() {}
765 };
766
767 class mpls_ai : public bs_length, public _mpls_ai {
768 public:
769   bd_uo_mask uo_mask;
770   int write();
771
772   mpls_ai() {}
773   ~mpls_ai() {}
774 };
775
776 class _mpls_sub_pi {
777 public:
778   uint8_t connection_condition;
779   uint8_t is_multi_clip;
780   uint32_t in_time;
781   uint32_t out_time;
782   uint16_t sync_play_item_id;
783   uint32_t sync_pts;
784
785   _mpls_sub_pi() { memset(this, 0, sizeof(*this)); }
786   ~_mpls_sub_pi() {}
787 };
788
789 class mpls_sub_pi : public bs_length, public _mpls_sub_pi {
790 public:
791   ArrayList<mpls_clip *> clip;
792   int write();
793
794   mpls_sub_pi() {}
795   ~mpls_sub_pi() {
796     clip.remove_all_objects();
797   }
798 };
799
800 class _mpls_sub {
801 public:
802   uint8_t type;
803   uint8_t is_repeat;
804
805   _mpls_sub() { memset(this, 0, sizeof(*this)); }
806   ~_mpls_sub() {}
807 };
808
809 class mpls_sub : public bs_length, public _mpls_sub {
810 public:
811   ArrayList<mpls_sub_pi *> sub_play_item;
812
813   int write();
814   mpls_sub() {}
815   ~mpls_sub() {
816    sub_play_item.remove_all_objects();
817   }
818 };
819
820 class _mpls_pip_data {
821 public:
822   uint32_t time;
823   uint16_t xpos;
824   uint16_t ypos;
825   uint8_t scale_factor;
826
827   _mpls_pip_data() { memset(this, 0, sizeof(*this)); }
828   ~_mpls_pip_data() {}
829 };
830
831 class mpls_pip_data : public _mpls_pip_data {
832 public:
833   int write();
834
835   mpls_pip_data() {}
836   ~mpls_pip_data() {}
837 };
838
839 class _mpls_pip_metadata {
840 public:
841   uint16_t clip_ref;
842   uint8_t secondary_video_ref;
843   uint8_t timeline_type;
844   uint8_t luma_key_flag;
845   uint8_t upper_limit_luma_key;
846   uint8_t trick_play_flag;
847
848   _mpls_pip_metadata() { memset(this, 0, sizeof(*this)); }
849   ~_mpls_pip_metadata() {}
850 };
851
852 class mpls_pip_metadata : public _mpls_pip_metadata {
853 public:
854   ArrayList<mpls_pip_data *> data;
855
856   int write(uint32_t start_address);
857   mpls_pip_metadata() {}
858   ~mpls_pip_metadata() {
859     data.remove_all_objects();
860   }
861 };
862
863 class _mpls_pl {
864 public:
865   uint32_t list_pos;
866   uint32_t mark_pos;
867   uint32_t ext_pos;
868
869   _mpls_pl() { memset(this, 0, sizeof(*this)); }
870   ~_mpls_pl() {}
871 };
872
873 class mpls_pl : public _mpls_pl {
874 public:
875   int sig;
876   bs_length play, mark, subx, pipm;
877   mpls_ai app_info;
878   ArrayList<mpls_pi *> play_item;
879   ArrayList<mpls_sub *> sub_path;
880   ArrayList<mpls_plm *> play_mark;
881   // extension data (profile 5, version 2.4)
882   ArrayList<mpls_sub *> ext_sub_path;
883   // extension data (Picture-In-Picture metadata)
884   ArrayList<mpls_pip_metadata *> ext_pip_data;
885
886   int write_header();
887   int write_playlist();
888   int write_playlistmark();
889   int write_subpath_extension();
890   int write_pip_metadata_extension();
891   int write();
892
893   mpls_pl() { sig = 1; }
894   ~mpls_pl() {
895     play_item.remove_all_objects();
896     sub_path.remove_all_objects();
897     play_mark.remove_all_objects();
898     ext_sub_path.remove_all_objects();
899     ext_pip_data.remove_all_objects();
900   }
901 };
902
903 class _clpi_cl {
904 public:
905   uint32_t sequence_info_start_addr;
906   uint32_t program_info_start_addr;
907   uint32_t cpi_start_addr;
908   uint32_t clip_mark_start_addr;
909   uint32_t ext_data_start_addr;
910
911   _clpi_cl() { memset(this, 0, sizeof(*this)); }
912   ~_clpi_cl() {}
913 };
914
915 class clpi_cl : public _clpi_cl {
916 public:
917   int sig;
918   clpi_clip_info clip;
919   clpi_sequences sequences;
920   clpi_programs programs;
921   clpi_cpi cpi;
922   clpi_extents extents;
923   clpi_programs programs_ss;
924   clpi_cpi cpi_ss;
925
926   int write_header();
927   int write();
928
929   int write_clpi_extension(int id1, int id2, void *handle);
930   int write_mpls_extension(int id1, int id2, void *handle);
931
932   clpi_cl() { sig = 1; }
933   ~clpi_cl() {}
934 };
935
936 class command_obj {
937 public:
938   union {
939     uint32_t cmd;
940     struct {
941       uint32_t sub_grp:3;       /* command sub-group */
942       uint32_t grp:2;           /* command group */
943       uint32_t op_cnt:3;        /* operand count */
944       uint32_t branch_opt:4;    /* branch option */
945       uint32_t rsvd1:2;
946       uint32_t imm_op2:1;       /* I-flag for operand 2 */
947       uint32_t imm_op1:1;       /* I-flag for operand 1 */
948       uint32_t cmp_opt:4;       /* compare option */
949       uint32_t rsvd2:4;
950       uint32_t set_opt:5;       /* set option */
951       uint32_t rsvd3:3;
952     };
953   };
954   uint32_t dst;
955   uint32_t src;
956
957   command_obj() { cmd = dst = src = 0; }
958   ~command_obj() {}
959 };
960
961 class _movie_obj {
962 public:
963   int resume_intention_flag;
964   int menu_call_mask;
965   int title_search_mask;
966
967   _movie_obj() { memset(this, 0, sizeof(*this)); }
968   ~_movie_obj() {}
969 };
970
971 class movie_obj : public _movie_obj {
972 public:
973   ArrayList<command_obj *> cmds;
974
975   movie_obj() {}
976   ~movie_obj() {
977     cmds.remove_all_objects();
978   }
979 };
980
981 class movie_file : public bs_length {
982 public:
983   int sig;
984   ArrayList<movie_obj *> movies;
985
986   movie_file() { sig = 1; }
987   ~movie_file() {
988     movies.remove_all_objects();
989   }
990
991   int write();
992 };
993
994 class _pb_obj {
995 public:
996   int obj_typ;
997   int pb_typ;
998   int hdmv_id;
999
1000   _pb_obj() { memset(this, 0, sizeof(*this)); }
1001   ~_pb_obj() {}
1002 };
1003
1004 class pb_obj : public _pb_obj {
1005 public:
1006   int last;
1007   char *bdj_name;
1008   void write_obj();
1009
1010   pb_obj() {
1011     last = 0;
1012     bdj_name = 0;
1013   }
1014   ~pb_obj() {
1015     delete [] bdj_name;
1016   }
1017
1018   void set_hdmv(int id, int pt);
1019   void set_bdj(char *nm, int pt);
1020   void write_hdmv_obj(int id_ref);
1021   void write_bdj_obj(char *name);
1022 };
1023
1024 class _title_obj {
1025 public:
1026   int acc_typ;
1027   _title_obj() { acc_typ = 0; }
1028   ~_title_obj() {}
1029 };
1030
1031 class title_obj : public pb_obj, public _title_obj {
1032 public:
1033   title_obj() {}
1034   ~title_obj() {}
1035
1036   void write_obj();
1037 };
1038
1039 class _index_file {
1040 public:
1041   int sig;
1042   int initial_output_mode_preference;
1043   int content_exist_flag;
1044   int video_format;
1045   int frame_rate;
1046
1047   _index_file() { memset(this, 0, sizeof(*this)); }
1048   ~_index_file() {}
1049 };
1050
1051 class index_file : public bs_length, public _index_file {
1052 public:
1053   ArrayList<title_obj *> titles;
1054   pb_obj first_play;
1055   pb_obj top_menu;
1056   char user_data[32];
1057   bs_length exten, appinf;
1058
1059   void write_hdmv_obj(int hdmv_typ, int id_ref);
1060   void write_bdj_obj(int bdj_typ, char *name);
1061   void write_pb_obj(pb_obj * pb);
1062   int write();
1063
1064   index_file() {
1065     sig = 1;
1066     memset(user_data, 0, sizeof(user_data));
1067   }
1068   ~index_file() {
1069     titles.remove_all_objects();
1070   }
1071 };
1072
1073 class _bdid {
1074 public:
1075   uint32_t data_start;
1076   uint32_t extension_data_start;
1077   char org_id[4];
1078   char disc_id[16];
1079
1080   _bdid() { memset(this, 0, sizeof(*this)); }
1081   ~_bdid() {}
1082 };
1083
1084 class bdid : public _bdid {
1085 public:
1086   int sig;
1087   int write();
1088
1089   bdid() { sig = 1; }
1090   ~bdid() {}
1091 };
1092
1093 class stream : public bd_stream_info {
1094 public:
1095   int av_idx;
1096   AVMediaType type;
1097   AVCodecID codec_id;
1098   int64_t start_pts;
1099   int64_t end_pts;
1100   int64_t last_pts;
1101   int64_t duration;
1102
1103   stream(AVMediaType ty, int i) {
1104     type = ty;  av_idx = i;
1105     start_pts = INT64_MAX; end_pts = INT64_MIN;
1106     last_pts = -1;
1107   }
1108   ~stream() {}
1109 };
1110
1111 class mark {
1112 public:
1113   static int cmpr(mark **, mark **);
1114   int64_t sample, pos, pts;
1115   uint32_t pkt, pid;
1116   mark(int64_t s, int64_t p, int64_t ts, uint32_t pk, int id) {
1117     sample = s;  pos = p;  pts = ts; pkt = pk;  pid = id;
1118   }
1119 };
1120
1121 int mark::cmpr(mark **a, mark **b)
1122 {
1123   mark *ap = *(mark **)a,  *bp = *(mark **)b;
1124   return ap->pts > bp->pts ? 1 : ap->pts < bp->pts ? -1 : 0;
1125 }
1126
1127 class _program {
1128 public:
1129   int pmt_pid, pcr_pid, ep_pid;
1130   int64_t start_time, end_time;
1131   int64_t duration;
1132   _program() {
1133     memset(this, 0, sizeof(*this));
1134     start_time = INT64_MAX; end_time = INT64_MIN;
1135   }
1136   ~_program() {}
1137 };
1138
1139 class program : public _program {
1140 public:
1141   int idx;
1142   uint16_t pid;
1143   ArrayList<int> strm_idx;
1144   ArrayList<mark*> marks;
1145   int64_t curr_pos;
1146   int build_toc(clpi_ep_map_entry *map);
1147   void add_label(uint32_t pk, int64_t p, int64_t ts, int id) {
1148     marks.append(new mark(curr_pos, p, ts, pk, id));
1149   }
1150
1151   program(int i, int id) { idx = i;  pid = id;  curr_pos = 0; }
1152   ~program() { marks.remove_all_objects(); }
1153 };
1154
1155 class _media_info {
1156 public:
1157   int bit_rate;
1158   int64_t file_size;
1159
1160   _media_info() {
1161     memset(this, 0, sizeof(*this));
1162   }
1163   ~_media_info() {}
1164 };
1165
1166 class media_info : public _media_info {
1167 public:
1168   static const AVRational clk45k;
1169   char filename[BCTEXTLEN];
1170   int pgm_pid;
1171   int brk, pidx, still;
1172   ArrayList<stream *> streams;
1173   ArrayList<program *> programs;
1174   program *prog()  { return programs[pidx]; }
1175
1176   media_info(const char *fn) {
1177     strcpy(filename, fn);
1178     brk = 0;  pidx = 0;  pgm_pid = -1;  still = 0;
1179   }
1180   ~media_info() {
1181     streams.remove_all_objects();
1182     programs.remove_all_objects();
1183   }
1184
1185   int scan();
1186   int scan(AVFormatContext *fmt_ctx);
1187 };
1188
1189 class Media : public ArrayList<media_info *> {
1190 public:
1191   char *path;
1192   char filename[BCTEXTLEN];
1193   int bd_path(const char *bp, const char *fmt, va_list ap);
1194   int bd_open(const char *fmt, ...);
1195   int bd_backup(const char *fmt, ...);
1196   int bd_copy(const char *ifn, const char *fmt, ...);
1197
1198   index_file idx;
1199   movie_file mov;
1200   ArrayList<clpi_cl *> cl;
1201   ArrayList<mpls_pl *> pl;
1202
1203   int compose();
1204   int write(char *fn);
1205
1206   Media() { path = 0;  filename[0] = 0; }
1207   ~Media() {
1208     remove_all_objects();
1209     cl.remove_all_objects();
1210     pl.remove_all_objects();
1211   }
1212 };
1213
1214 #endif
1215
1216 void bs_file::init()
1217 {
1218   fp = 0;
1219   reg = len = 0;
1220   fpos = fsz = 0;
1221 }
1222
1223 int
1224 bs_file::open(const char *fn)
1225 {
1226   fp = fopen(fn,"w");
1227   if( !fp ) perror(fn);
1228   return fp != 0 ? 0 : 1;
1229 }
1230
1231 void
1232 bs_file::close()
1233 {
1234   if( fp ) { fclose(fp); fp = 0; }
1235 }
1236
1237 void
1238 bs_file::write(uint32_t v, int n)
1239 {
1240   uint64_t vv = reg;
1241   vv <<= n;  vv |= v;
1242   reg = vv;  len += n;
1243   while( len >= 8 ) {
1244     len -= 8;
1245     if( fp ) fputc((vv >> len), fp);
1246     if( ++fpos > fsz ) fsz = fpos;
1247   }
1248 }
1249
1250 void
1251 bs_file::writeb(uint8_t * bp, int n)
1252 {
1253   while( --n >= 0 ) write(*bp++, 8);
1254 }
1255
1256 void
1257 bs_file::pad(int n)
1258 {
1259   while( n > 32 ) { write(0, 32);  n -= 32; }
1260   if( n > 0 ) write(0, n);
1261 }
1262
1263 void
1264 bs_file::posb(int64_t n)
1265 {
1266   if( fpos == fsz && n > fpos ) {
1267     padb(n-fpos);
1268     return;
1269   }
1270   fpos = n;
1271   if( fp ) fseek(fp, fpos, SEEK_SET);
1272 }
1273
1274 static bs_file bs;
1275
1276
1277 int
1278 movie_file::write()
1279 {
1280   // output header
1281   bs.writeb("MOBJ", 4);
1282   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1283   int movie_start = 0x0028;
1284   bs.posb(movie_start);
1285   bs_len(bs, 32);
1286   bs.write(0, 32);
1287   bs.write(movies.size(), 16);
1288
1289   for (int i = 0; i < movies.size(); ++i) {
1290     movie_obj *mov = movies[i];
1291     bs.write(mov->resume_intention_flag, 1);
1292     bs.write(mov->menu_call_mask, 1);
1293     bs.write(mov->title_search_mask, 1);
1294     bs.write(0, 13);
1295     ArrayList<command_obj *> &cmds = mov->cmds;
1296     int num_cmds = cmds.size();
1297     bs.write(num_cmds, 16);
1298     for (int j = 0; j < num_cmds; ++j) {
1299       command_obj *cmd = cmds[j];
1300       bs.write(cmd->op_cnt, 3);
1301       bs.write(cmd->grp, 2);
1302       bs.write(cmd->sub_grp, 3);
1303       bs.write(cmd->imm_op1, 1);
1304       bs.write(cmd->imm_op2, 1);
1305       bs.write(0, 2);
1306       bs.write(cmd->branch_opt, 4);
1307       bs.write(0, 4);
1308       bs.write(cmd->cmp_opt, 4);
1309       bs.write(0, 3);
1310       bs.write(cmd->set_opt, 5);
1311       //bs.write(cmd->cmd, 32);
1312       bs.write(cmd->dst, 32);
1313       bs.write(cmd->src, 32);
1314     }
1315   }
1316 //in sony AVCHD
1317 //  bs.write('l', 8);
1318 //  bs.writebcd(year, 16);
1319 //  bs.writebcd(month, 8);
1320 //  bs.writebcd(day, 8);
1321 //  bs.writebcd(hour, 8);
1322 //  bs.writebcd(min, 8);
1323 //  bs.writebcd(sec, 8);
1324   bs_end(bs);
1325   return 0;
1326 }
1327
1328 void
1329 pb_obj::set_hdmv(int id, int pt)
1330 {
1331   obj_typ = obj_hdmv;
1332   pb_typ = pt;
1333   delete [] bdj_name;
1334   bdj_name = 0;
1335   hdmv_id = id;
1336 }
1337
1338 void
1339 pb_obj::set_bdj(char *nm, int pt)
1340 {
1341   obj_typ = obj_bdj;
1342   pb_typ = pt;
1343   delete [] bdj_name;
1344   bdj_name = 0;
1345   bdj_name = cstrdup(nm);
1346 }
1347
1348 void 
1349 pb_obj::write_hdmv_obj(int id_ref)
1350 {
1351   bs.write(pb_typ, 2);
1352   bs.write(0, 14);
1353   bs.write(id_ref, 16);
1354   bs.write(0, 32);
1355 }
1356
1357 void
1358 pb_obj::write_bdj_obj(char *name)
1359 {
1360   bs.write(pb_typ, 2);
1361   bs.write(0, 14);
1362   bs.writeb(name, 5);
1363   bs.write(0, 8);
1364 }
1365
1366 void
1367 pb_obj::write_obj()
1368 {
1369   switch (obj_typ) {
1370   case obj_bdj:
1371     write_bdj_obj(bdj_name);
1372     break;
1373   case obj_hdmv:
1374   default:
1375     write_hdmv_obj(hdmv_id);
1376     break;
1377   }
1378 }
1379
1380 void
1381 title_obj::write_obj()
1382 {
1383   bs.write(obj_typ, 2);
1384   bs.write(acc_typ, 2);
1385   bs.write(0, 28);
1386   pb_obj::write_obj();
1387 }
1388
1389
1390 void
1391 index_file::write_pb_obj(pb_obj * pb)
1392 {
1393   bs.write(pb->obj_typ, 2);
1394   bs.write(0, 30);
1395   pb->write_obj();
1396 }
1397
1398 int
1399 index_file::write()
1400 {
1401   // output header
1402   bs.writeb("INDX", 4);
1403   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1404   bs_ofs(bs, 32);
1405   exten.bs_ofs(bs, 32);
1406   int appinfo_start = 0x28;
1407   bs.posb(appinfo_start);
1408   appinf.bs_len(bs, 32);
1409   bs.write(1, 1);
1410   bs.write(initial_output_mode_preference, 1);
1411   bs.write(content_exist_flag, 1);
1412   bs.write(0, 5);
1413   bs.write(video_format, 4);
1414   bs.write(frame_rate, 4);
1415   bs.writeb(user_data, 32);
1416   appinf.bs_end(bs);
1417
1418   // output index
1419   bs_len(bs, 32);
1420   write_pb_obj(&first_play);
1421   write_pb_obj(&top_menu);
1422   bs.write(titles.size(), 16);
1423
1424   for (int i = 0; i < titles.size(); ++i)
1425     titles[i]->write_obj();
1426   bs_end(bs);
1427   exten.bs_len(bs,32);
1428   exten.bs_end(bs);
1429   return 0;
1430 }
1431
1432
1433
1434 int
1435 bdid::write()
1436 {
1437   bs.writeb("BDID",4);
1438   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1439   bs.write(data_start, 32);
1440   bs.write(extension_data_start, 32);
1441   bs.posb(40 - 16);
1442   bs.writeb(org_id, sizeof(org_id));
1443   bs.writeb(disc_id, sizeof(disc_id));
1444   return 0;
1445 }
1446
1447 // XXX - not current referenced
1448 #if 0
1449 int
1450 bdmv_write_extension_data(int start_address,
1451         int (*handler) (int, int, void *), void *handle)
1452 {
1453   int64_t length;
1454   int num_entries, n;
1455
1456   bs.write(length, 32);   /* length of extension data block */
1457   if( length < 1 )
1458     return 1;
1459
1460   bs.pad(32);             /* relative start address of extension data */
1461   bs.pad(24);             /* padding */
1462   bs.write(num_entries, 8);
1463
1464   for (n = 0; n < num_entries; n++) {
1465     bs.write(id1, 16);
1466     bs.write(id2, 16);
1467     bs.write(ext_start, 32);
1468     bs.write(ext_len, 32);
1469     saved_pos = bs.pos() >> 3;
1470     bs.posb(start_address + ext_start);
1471     handler(id1, id2, handle);
1472     bs.posb(saved_pos);
1473   }
1474
1475   return 0;
1476 }
1477 #endif
1478
1479 int
1480 clpi_prog_stream::write()
1481 {
1482   bs.write(pid, 16);
1483   bs_len(bs, 8);
1484
1485   bs.write(coding_type, 8);
1486   switch (coding_type) {
1487   case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1488   case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1489   case BLURAY_STREAM_TYPE_VIDEO_VC1:
1490   case BLURAY_STREAM_TYPE_VIDEO_H264:
1491   case 0x20:
1492     bs.write(format, 4);
1493     bs.write(rate, 4);
1494     bs.write(aspect, 4);
1495     bs.pad(2);
1496     bs.write(oc_flag, 1);
1497     bs.pad(1);
1498     break;
1499
1500   case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1501   case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1502   case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1503   case BLURAY_STREAM_TYPE_AUDIO_AC3:
1504   case BLURAY_STREAM_TYPE_AUDIO_DTS:
1505   case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1506   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1507   case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1508   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1509   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1510   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1511     bs.write(format, 4);
1512     bs.write(rate, 4);
1513     bs.writeb(lang, 3);
1514     break;
1515
1516   case BLURAY_STREAM_TYPE_SUB_PG:
1517   case BLURAY_STREAM_TYPE_SUB_IG:
1518   case 0xa0:
1519     bs.writeb(lang, 3);
1520     break;
1521
1522   case BLURAY_STREAM_TYPE_SUB_TEXT:
1523     bs.write(char_code, 8);
1524     bs.writeb(lang, 3);
1525     break;
1526
1527   default:
1528     fprintf(stderr, "clpi_prog_stream: unrecognized coding type %02x\n",
1529             coding_type);
1530     return 1;
1531   };
1532
1533   bs_end(bs);
1534   return 0;
1535 }
1536
1537 int
1538 clpi_cl::write_header()
1539 {
1540   bs.writeb("HDMV", 4);
1541   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1542   bs.write(sequence_info_start_addr, 32);
1543   bs.write(program_info_start_addr, 32);
1544   bs.write(cpi_start_addr, 32);
1545   bs.write(clip_mark_start_addr, 32);
1546   bs.write(ext_data_start_addr, 32);
1547   return 0;
1548 }
1549
1550 int
1551 clpi_atc_delta::write()
1552 {
1553   bs.write(delta, 32);
1554   bs.writeb(file_id, 5);
1555   bs.writeb(file_code, 4);
1556   bs.pad(8);
1557   return 0;
1558 }
1559
1560 int
1561 clpi_clip_info::write()
1562 {
1563   bs.posb(40);
1564   bs_len(bs, 32);
1565
1566   bs.pad(16);                   // reserved
1567   bs.write(clip_stream_type, 8);
1568   bs.write(application_type, 8);
1569   bs.pad(31);                   // skip reserved 31 bits
1570   bs.write(is_atc_delta, 1);
1571   bs.write(ts_recording_rate, 32);
1572   bs.write(num_source_packets, 32);
1573
1574   bs.padb(128);                 // Skip reserved 128 bytes
1575
1576   // ts type info block
1577   int ts_len = 30;
1578   bs.write(ts_len, 16);
1579   int64_t pos = bs.posb();
1580   if( ts_len ) {
1581     bs.write(ts_type_info.validity, 8);
1582     bs.writeb(ts_type_info.format_id, 4);
1583     // pad the stuff we don't know anything about
1584     bs.padb(ts_len - (bs.posb() - pos));
1585   }
1586
1587   if( is_atc_delta ) {
1588     bs.pad(8);                  // Skip reserved byte
1589     bs.write(atc_delta.size(), 8);
1590     for( int ii=0; ii < atc_delta.size(); ++ii )
1591       if( atc_delta[ii]->write() ) return 1;
1592   }
1593
1594   // font info
1595   if( application_type == 6 /* Sub TS for a sub-path of Text subtitle */  ) {
1596     bs.pad(8);
1597     bs.write(font_info.font.size(), 8);
1598     if( font_info.font.size() ) {
1599       for( int ii=0; ii < font_info.font.size(); ++ii ) {
1600         bs.writeb(font_info.font[ii]->file_id, 5);
1601         bs.pad(8);
1602       }
1603     }
1604   }
1605
1606   bs_end(bs);
1607   return 0;
1608 }
1609
1610 int
1611 clpi_stc_seq::write()
1612 {
1613   bs.write(pcr_pid, 16);
1614   bs.write(spn_stc_start, 32);
1615   bs.write(presentation_start_time, 32);
1616   bs.write(presentation_end_time, 32);
1617   return 0;
1618 }
1619
1620 int
1621 clpi_atc_seq::write()
1622 {
1623   bs.write(spn_atc_start, 32);
1624   bs.write(stc_seq.size(), 8);
1625   bs.write(offset_stc_id, 8);
1626
1627   for( int ii=0; ii < stc_seq.size(); ++ii )
1628     if( stc_seq[ii]->write() ) return 1;
1629   return 0;
1630 }
1631
1632 int
1633 clpi_sequences::write()
1634 {
1635   bs_len(bs, 32);
1636   bs.padb(1);                   // reserved byte
1637   bs.write(size(), 8);
1638   for( int ii=0; ii < size(); ++ii )
1639     if( get(ii)->write() ) return 1;
1640   bs_end(bs);
1641   return 0;
1642 }
1643
1644 int
1645 clpi_prog::write()
1646 {
1647   bs.write(spn_program_sequence_start, 32);
1648   bs.write(program_map_pid, 16);
1649   bs.write(streams.size(), 8);
1650   bs.write(num_groups, 8);
1651   for( int ii=0; ii < streams.size(); ++ii )
1652     if( streams[ii]->write() ) return 1;
1653   return 0;
1654 }
1655
1656 int
1657 clpi_programs::write()
1658 {
1659   bs_len(bs, 32);
1660   bs.padb(1);                   // reserved byte
1661   bs.write(size(), 8);
1662   for( int ii=0; ii < size(); ++ii )
1663     if( get(ii)->write() ) return 1;
1664   bs_end(bs);
1665   return 0;
1666 }
1667
1668 int
1669 clpi_ep_coarse::write()
1670 {
1671   bs.write(ref_ep_fine_id, 18);
1672   bs.write(pts_ep, 14);
1673   bs.write(spn_ep, 32);
1674   return 0;
1675 }
1676
1677 int
1678 clpi_ep_fine::write()
1679 {
1680   bs.write(is_angle_change_point, 1);
1681   bs.write(i_end_position_offset, 3);
1682   bs.write(pts_ep, 11);
1683   bs.write(spn_ep, 17);
1684   return 0;
1685 }
1686
1687 int
1688 clpi_ep_map_entry::write(uint32_t ep_map_pos)
1689 {
1690   bs.write(pid, 16);
1691   bs.pad(10);
1692   bs.write(ep_stream_type, 4);
1693   bs.write(coarse.size(), 16);
1694   bs.write(fine.size(), 18);
1695   bs.write(ep_map_stream_start_addr - ep_map_pos, 32);
1696   return 0;
1697 }
1698
1699 int
1700 clpi_ep_map_entry::write_map()
1701 {
1702   ep_map_stream_start_addr = bs.posb();
1703   bs.write(fine_start, 32);
1704
1705   for( int ii=0; ii < coarse.size(); ++ii )
1706     if( coarse[ii]->write() ) return 1;
1707
1708   fine_start = bs.posb() - ep_map_stream_start_addr;
1709   for( int ii=0; ii < fine.size(); ++ii )
1710     if( fine[ii]->write() ) return 1;
1711
1712   return 0;
1713 }
1714
1715 int
1716 clpi_cpi::write()
1717 {
1718   bs_len(bs, 32);
1719   bs.pad(12);
1720   bs.write(type, 4);
1721   uint32_t ep_map_pos = bs.posb();
1722
1723   // EP Map starts here
1724   bs.pad(8);
1725   bs.write(size(), 8);
1726
1727   for( int ii=0; ii < size(); ++ii )
1728     if( get(ii)->write(ep_map_pos) ) return 1;
1729
1730   for( int ii=0; ii < size(); ++ii )
1731     if( get(ii)->write_map() ) return 1;
1732
1733   bs_end(bs);
1734   return 0;
1735 }
1736
1737 int
1738 clpi_extents::write()
1739 {
1740   bs_len(bs, 32);
1741   bs.write(size(), 32);
1742   for( int ii=0; ii < size(); ++ii )
1743     bs.write(get(ii), 32);
1744   return 0;
1745 }
1746
1747 int
1748 clpi_cl::write_clpi_extension(int id1, int id2, void *handle)
1749 {
1750   clpi_cl *cl = (clpi_cl *) handle;
1751
1752   if( id1 == 1 ) {
1753     if( id2 == 2 ) {
1754       // LPCM down mix coefficient
1755       //write_lpcm_down_mix_coeff(&cl->lpcm_down_mix_coeff);
1756       return 0;
1757     }
1758   }
1759
1760   if( id1 == 2 ) {
1761     if( id2 == 4 ) {
1762       // Extent start point
1763       return cl->extents.write();
1764     }
1765     if( id2 == 5 ) {
1766       // ProgramInfo SS
1767       return cl->programs_ss.write();
1768     }
1769     if( id2 == 6 ) {
1770       // CPI SS
1771       return cl->cpi_ss.write();
1772     }
1773   }
1774
1775   fprintf(stderr, "write_clpi_extension(): unhandled extension %d.%d\n", id1, id2);
1776   return 1;
1777 }
1778
1779 int
1780 clpi_cl::write()
1781 {
1782   if( write_header() ) return 1;
1783   if( clip.write() ) return 1;
1784   sequence_info_start_addr = bs.posb();
1785   if( sequences.write() ) return 1;
1786   program_info_start_addr = bs.posb();
1787   if( programs.write() ) return 1;
1788   cpi_start_addr = bs.posb();
1789   if( cpi.write() ) return 1;
1790 //if( has_ext_data ) {
1791 //  ext_data_start_addr = bs.pos();
1792 //  bdmv_write_extension_data(write_clpi_extension, this);
1793 //}
1794   return 0;
1795 }
1796
1797 int
1798 bd_uo_mask::write()
1799 {
1800   bs.write(menu_call, 1);
1801   bs.write(title_search, 1);
1802   bs.write(chapter_search, 1);
1803   bs.write(time_search, 1);
1804   bs.write(skip_to_next_point, 1);
1805   bs.write(skip_to_prev_point, 1);
1806   bs.write(play_firstplay, 1);
1807   bs.write(stop, 1);
1808   bs.write(pause_on, 1);
1809   bs.write(pause_off, 1);
1810   bs.write(still_off, 1);
1811   bs.write(forward, 1);
1812   bs.write(backward, 1);
1813   bs.write(resume, 1);
1814   bs.write(move_up, 1);
1815   bs.write(move_down, 1);
1816   bs.write(move_left, 1);
1817   bs.write(move_right, 1);
1818   bs.write(select, 1);
1819   bs.write(activate, 1);
1820   bs.write(select_and_activate, 1);
1821   bs.write(primary_audio_change, 1);
1822   bs.pad(1);
1823   bs.write(angle_change, 1);
1824   bs.write(popup_on, 1);
1825   bs.write(popup_off, 1);
1826   bs.write(pg_enable_disable, 1);
1827   bs.write(pg_change, 1);
1828   bs.write(secondary_video_enable_disable, 1);
1829   bs.write(secondary_video_change, 1);
1830   bs.write(secondary_audio_enable_disable, 1);
1831   bs.write(secondary_audio_change, 1);
1832   bs.pad(1);
1833   bs.write(pip_pg_change, 1);
1834   bs.pad(30);
1835   return 0;
1836 }
1837
1838 int
1839 mpls_ai::write()
1840 {
1841   bs_len(bs, 32);
1842   bs.pad(8);              // Reserved
1843   bs.write(playback_type, 8);
1844   if (playback_type == BLURAY_PLAYBACK_TYPE_RANDOM ||
1845       playback_type == BLURAY_PLAYBACK_TYPE_SHUFFLE ) {
1846     bs.write(playback_count, 16);
1847   }
1848   else {
1849     bs.pad(16);           // Reserved
1850   }
1851   uo_mask.write();
1852   bs.write(random_access_flag, 1);
1853   bs.write(audio_mix_flag, 1);
1854   bs.write(lossless_bypass_flag, 1);
1855   bs.pad(13);             // Reserved
1856   bs_end(bs);
1857   return 0;
1858 }
1859
1860 int
1861 mpls_pl::write_header()
1862 {
1863   bs.writeb("MPLS", 4);
1864   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1865   bs.write(list_pos, 32);
1866   bs.write(mark_pos, 32);
1867   bs.write(ext_pos, 32);
1868   bs.pad(160);            // Skip 160 reserved bits
1869   app_info.write();
1870   return 0;
1871 }
1872
1873 int mpls_stream::
1874 write()
1875 {
1876   strm.bs_len(bs, 8);
1877
1878   bs.write(stream_type, 8);
1879   switch (stream_type) {
1880   case 0x01:
1881     bs.write(pid, 16);
1882     break;
1883
1884   case 0x02:
1885   case 0x04:
1886     bs.write(subpath_id, 8);
1887     bs.write(subclip_id, 8);
1888     bs.write(pid, 16);
1889     break;
1890
1891   case 0x03:
1892     bs.write(subpath_id, 8);
1893     bs.write(pid, 16);
1894     break;
1895
1896   default:
1897     fprintf(stderr, "unrecognized stream type %02x\n", stream_type);
1898     break;
1899   };
1900   strm.bs_end(bs);
1901
1902   code.bs_len(bs, 8);
1903   bs.write(coding_type, 8);
1904   switch (coding_type) {
1905   case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1906   case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1907   case BLURAY_STREAM_TYPE_VIDEO_VC1:
1908   case BLURAY_STREAM_TYPE_VIDEO_H264:
1909     bs.write(format, 4);
1910     bs.write(rate, 4);
1911     break;
1912
1913   case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1914   case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1915   case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1916   case BLURAY_STREAM_TYPE_AUDIO_AC3:
1917   case BLURAY_STREAM_TYPE_AUDIO_DTS:
1918   case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1919   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1920   case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1921   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1922   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1923   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1924     bs.write(format, 4);
1925     bs.write(rate, 4);
1926     bs.writeb(lang, 3);
1927     break;
1928
1929   case BLURAY_STREAM_TYPE_SUB_PG:
1930   case BLURAY_STREAM_TYPE_SUB_IG:
1931     bs.writeb(lang, 3);
1932     break;
1933
1934   case BLURAY_STREAM_TYPE_SUB_TEXT:
1935     bs.write(char_code, 8);
1936     bs.writeb(lang, 3);
1937     break;
1938
1939   default:
1940     fprintf(stderr, "mpls_stream: unrecognized coding type %02x\n", coding_type);
1941     break;
1942   };
1943   code.bs_end(bs);
1944   return 0;
1945 }
1946
1947 int
1948 mpls_stn::write()
1949 {
1950   bs_len(bs, 16);
1951   bs.pad(16);             // Skip 2 reserved bytes
1952
1953   bs.write(video.size(), 8);
1954   bs.write(audio.size(), 8);
1955   bs.write(pg.size() - num_pip_pg, 8);
1956   bs.write(ig.size(), 8);
1957   bs.write(secondary_audio.size(), 8);
1958   bs.write(secondary_video.size(), 8);
1959   bs.write(num_pip_pg, 8);
1960
1961   // 5 reserve bytes
1962   bs.pad(5 * 8);
1963
1964   // Primary Video Streams
1965   for( int ii=0; ii < video.size(); ++ii )
1966     if( video[ii]->write() ) return 1;
1967
1968   // Primary Audio Streams
1969   for( int ii=0; ii < audio.size(); ++ii )
1970     if( audio[ii]->write() ) return 1;
1971
1972   // Presentation Graphic Streams
1973   for( int ii=0; ii < pg.size(); ++ii )
1974     if( pg[ii]->write() ) return 1;
1975
1976   // Interactive Graphic Streams
1977   for( int ii=0; ii < ig.size(); ++ii )
1978     if( ig[ii]->write() ) return 1;
1979
1980   // Secondary Audio Streams
1981   for( int ii=0; ii < secondary_audio.size(); ++ii ) {
1982     if( secondary_audio[ii]->write() ) return 1;
1983     // Read Secondary Audio Extra Attributes
1984     bs.write(sa_primary_audio_ref.size(), 8);
1985     bs.pad(8);
1986     for( int jj=0; jj < sa_primary_audio_ref.size(); ++jj )
1987       bs.write(sa_primary_audio_ref[jj], 8);
1988     if( sa_primary_audio_ref.size() % 2) bs.pad(8 );
1989   }
1990
1991   // Secondary Video Streams
1992   for( int ii=0; ii < secondary_video.size(); ++ii ) {
1993     if( secondary_video[ii]->write() ) return 1;
1994     // Read Secondary Video Extra Attributes
1995     bs.write(sv_secondary_audio_ref.size(), 8);
1996     bs.pad(8);
1997     for( int jj=0; jj < sv_secondary_audio_ref.size(); ++jj )
1998       bs.write(sv_secondary_audio_ref[jj], 8);
1999     if( sv_secondary_audio_ref.size() % 2) bs.pad(8 );
2000     bs.write(sv_pip_pg_ref.size(), 8);
2001     bs.pad(8);
2002     for( int jj=0; jj < sv_pip_pg_ref.size(); ++jj )
2003       bs.write(sv_pip_pg_ref[jj], 8);
2004     if( sv_pip_pg_ref.size() % 2) bs.pad(8 );
2005   }
2006
2007   bs_end(bs);
2008   return 0;
2009 }
2010
2011 int
2012 mpls_pi::write()
2013 {
2014   bs_len(bs, 16);
2015   // Primary Clip identifer
2016   bs.writeb(clip[0]->clip_id, 5);
2017   bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2018   bs.pad(11); // Skip reserved 11 bits
2019
2020   bs.write(is_multi_angle, 1);
2021   bs.write(connection_condition, 4);  // 0x01, 0x05, 0x06
2022
2023   bs.write(clip[0]->stc_id, 8);
2024   bs.write(in_time, 32);
2025   bs.write(out_time, 32);
2026
2027   uo_mask.write();
2028   bs.write(random_access_flag, 1);
2029   bs.pad(7);
2030   bs.write(still_mode, 8);
2031   if( still_mode == 0x01 ) {
2032     bs.write(still_time, 16);
2033   }
2034   else {
2035     bs.pad(16);
2036   }
2037
2038   if( is_multi_angle ) {
2039     bs.write(clip.size(), 8);
2040     bs.pad(6);
2041     bs.write(is_different_audio, 1);
2042     bs.write(is_seamless_angle, 1);
2043   }
2044
2045   for( int ii=1; ii < clip.size(); ++ii ) {
2046     bs.writeb(clip[ii]->clip_id, 5);
2047     bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2048     bs.write(clip[ii]->stc_id, 8);
2049   }
2050
2051   if( stn.write() ) return 1;
2052
2053   bs_end(bs);
2054   return 0;
2055 }
2056
2057 int
2058 mpls_sub_pi::write()
2059 {
2060   bs_len(bs, 16);
2061   // Primary Clip identifer
2062   bs.writeb(clip[0]->clip_id, 5);
2063   bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2064   bs.pad(27);
2065
2066   bs.write(connection_condition, 4); // 0x01, 0x05, 0x06
2067
2068   bs.write(is_multi_clip, 1);
2069   bs.write(clip[0]->stc_id, 8);
2070   bs.write(in_time, 32);
2071   bs.write(out_time, 32);
2072   bs.write(sync_play_item_id, 16);
2073   bs.write(sync_pts, 32);
2074
2075   if( is_multi_clip )
2076     bs.write(clip.size(), 8);
2077
2078   for( int ii=1; ii < clip.size(); ++ii ) {
2079     // Primary Clip identifer
2080     bs.writeb(clip[ii]->clip_id, 5);
2081     bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2082     bs.write(clip[ii]->stc_id, 8);
2083   }
2084
2085   bs_end(bs);
2086   return 0;
2087 }
2088
2089 int
2090 mpls_sub::write()
2091 {
2092   bs_len(bs, 32);
2093   bs.pad(8);
2094   bs.write(type, 8);
2095   bs.pad(15);
2096   bs.write(is_repeat, 1);
2097   bs.pad(8);
2098   bs.write(sub_play_item.size(), 8);
2099
2100   for( int ii=0; ii < sub_play_item.size(); ++ii )
2101     if( sub_play_item[ii]->write() ) return 1;
2102
2103   bs_end(bs);
2104   return 0;
2105 }
2106
2107 int
2108 mpls_plm::write()
2109 {
2110   bs.write(mark_id, 8);
2111   bs.write(mark_type, 8);
2112   bs.write(play_item_ref, 16);
2113   bs.write(time, 32);
2114   bs.write(entry_es_pid, 16);
2115   bs.write(duration, 32);
2116   return 0;
2117 }
2118
2119 int
2120 mpls_pl::write_playlistmark()
2121 {
2122   mark.bs_len(bs, 32);
2123   // Then get the number of marks
2124   bs.write(play_mark.size(), 16);
2125
2126   for( int ii=0; ii < play_mark.size(); ++ii )
2127     if( play_mark[ii]->write() ) return 1;
2128
2129   mark.bs_end(bs);
2130   return 0;
2131 }
2132
2133 int
2134 mpls_pl::write_playlist()
2135 {
2136   play.bs_len(bs,32);
2137
2138   // Skip reserved bytes
2139   bs.pad(16);
2140
2141   bs.write(play_item.size(), 16);
2142   bs.write(sub_path.size(), 16);
2143
2144   for( int ii=0; ii < play_item.size(); ++ii )
2145     if( play_item[ii]->write() ) return 1;
2146
2147   for( int ii=0; ii < sub_path.size(); ++ii )
2148     if( sub_path[ii]->write() ) return 1;
2149
2150   play.bs_end(bs);
2151   return 0;
2152 }
2153
2154 int
2155 mpls_pip_data::write()
2156 {
2157   bs.write(time, 32);
2158   bs.write(xpos, 12);
2159   bs.write(ypos, 12);
2160   bs.write(scale_factor, 4);
2161   bs.pad(4);
2162   return 0;
2163 }
2164
2165 int
2166 mpls_pip_metadata::write(uint32_t start_address)
2167 {
2168
2169   bs.write(clip_ref, 16);
2170   bs.write(secondary_video_ref, 8);
2171   bs.pad(8);
2172   bs.write(timeline_type, 4);
2173   bs.write(luma_key_flag, 1);
2174   bs.write(trick_play_flag, 1);
2175   bs.pad(10);
2176   if( luma_key_flag ) {
2177     bs.pad(8);
2178     bs.write(upper_limit_luma_key, 8);
2179   }
2180   else {
2181     bs.pad(16);
2182   }
2183   bs.pad(16);
2184
2185   uint32_t data_address = 0;  // XXX
2186   bs.write(data_address, 32);
2187
2188   int64_t pos = bs.pos() / 8;
2189   bs.posb(start_address + data_address);
2190
2191   bs.write(data.size(), 16);
2192   if( data.size() < 1 ) return 1;
2193
2194   for( int ii=0; ii < data.size(); ++ii )
2195     if( data[ii]->write() ) return 1;
2196
2197   bs.posb(pos);
2198   return 0;
2199 }
2200
2201 int
2202 mpls_pl::write_pip_metadata_extension()
2203 {
2204   uint32_t pos = bs.posb();
2205   pipm.bs_len(bs, 32);
2206
2207   bs.write(ext_pip_data.size(), 16);
2208   for( int ii=0; ii < ext_pip_data.size(); ++ii )
2209     if( ext_pip_data[ii]->write(pos) ) return 1;
2210
2211   pipm.bs_end(bs);
2212   return 0;
2213 }
2214
2215 int
2216 mpls_pl::write_subpath_extension()
2217 {
2218   subx.bs_len(bs, 32);
2219
2220   bs.write(ext_sub_path.size(), 16);
2221   for( int ii=0; ii < ext_sub_path.size(); ++ii )
2222     if( ext_sub_path[ii]->write() ) return 1;
2223
2224   subx.bs_end(bs);
2225   return 0;
2226 }
2227
2228 int
2229 clpi_cl::write_mpls_extension(int id1, int id2, void *handle)
2230 {
2231   mpls_pl *pl = (mpls_pl *) handle;
2232
2233   if( id1 == 1 ) {
2234     if( id2 == 1 ) {
2235       // PiP metadata extension
2236       return pl->write_pip_metadata_extension();
2237     }
2238   }
2239
2240   if( id1 == 2 ) {
2241     if( id2 == 1 ) {
2242       return 0;
2243     }
2244     if( id2 == 2 ) {
2245       // SubPath entries extension
2246       return pl->write_subpath_extension();
2247     }
2248   }
2249
2250   return 0;
2251 }
2252
2253 int mpls_pl::
2254 write()
2255 {
2256   int ret = write_header();
2257   list_pos = bs.posb();;
2258   if( !ret ) ret = write_playlist();
2259   mark_pos = bs.posb();
2260   if( !ret ) ret = write_playlistmark();
2261 //if( has_pls_extension ) {
2262 //  ext_pos = bs.posb();
2263 //  bdmv_write_extension_data(write_mpls_extension, pl);
2264   return ret;
2265 }
2266
2267 static int
2268 mk_dir(char *path)
2269 {
2270   if( !mkdir(path, 0777) )
2271     return 0;
2272   perror(path);
2273   return 1;
2274 }
2275
2276 static int
2277 mk_bdmv_dir(char *bdmv_path)
2278 {
2279   if( mk_dir(bdmv_path) )
2280     return 1;
2281   char bdjo_path[BCTEXTLEN];
2282   sprintf(bdjo_path, "%s/BDJO", bdmv_path);
2283   if( mk_dir(bdjo_path) )
2284     return 1;
2285   char clipinf_path[BCTEXTLEN];
2286   sprintf(clipinf_path, "%s/CLIPINF", bdmv_path);
2287   if( mk_dir(clipinf_path) )
2288     return 1;
2289   char jar_path[BCTEXTLEN];
2290   sprintf(jar_path, "%s/JAR", bdmv_path);
2291   if( mk_dir(jar_path) )
2292     return 1;
2293   char playlist_path[BCTEXTLEN];
2294   sprintf(playlist_path, "%s/PLAYLIST", bdmv_path);
2295   if( mk_dir(playlist_path) )
2296     return 1;
2297   return 0;
2298 }
2299
2300 static int
2301 mkbdmv(char *path)
2302 {
2303   char bdmv_path[BCTEXTLEN];
2304   sprintf(bdmv_path, "%s/BDMV", path);
2305   if( mk_bdmv_dir(bdmv_path) ) return 1;
2306   char stream_path[BCTEXTLEN];
2307   sprintf(stream_path, "%s/BDMV/STREAM", path);
2308   if( mk_dir(stream_path) ) return 1;
2309   char auxdata_path[BCTEXTLEN];
2310   sprintf(auxdata_path, "%s/BDMV/AUXDATA", path);
2311   if( mk_dir(auxdata_path) ) return 1;
2312   char meta_path[BCTEXTLEN];
2313   sprintf(meta_path, "%s/BDMV/META", path);
2314   if( mk_dir(meta_path) ) return 1;
2315   char backup_path[BCTEXTLEN];
2316   sprintf(backup_path, "%s/BACKUP", bdmv_path);
2317   if( mk_bdmv_dir(backup_path) ) return 1;
2318   return 0;
2319 }
2320
2321 int program::
2322 build_toc(clpi_ep_map_entry *map)
2323 {
2324   clpi_ep_coarse *cp = 0;
2325   marks.sort(mark::cmpr);
2326   uint16_t ep_pid = map->pid;
2327   int64_t last_pts = -1, last_pkt = -1;
2328   for( int ii=0; ii<marks.size(); ++ii ) {
2329     mark *mp = marks[ii];
2330     if( mp->pid != ep_pid ) continue;
2331     int64_t pts = mp->pts;
2332     if( last_pts >= pts ) continue;
2333     last_pts = pts;
2334     uint32_t pkt = mp->pos / BLURAY_TS_PKTSZ;
2335     if( last_pkt >= pkt ) continue;
2336     last_pkt = pkt;
2337     int64_t coarse_pts = (pts >> 18) & ~0x01;
2338     int64_t fine_pts = (pts & 0x7ffff) >> 8;
2339     uint32_t mpkt = pkt & ~0x1ffff;
2340     if( !cp || cp->pts_ep != coarse_pts || cp->spn_ep != mpkt ) {
2341       cp = new clpi_ep_coarse();
2342       map->coarse.append(cp);
2343       cp->ref_ep_fine_id = map->fine.size();
2344       cp->pts_ep = coarse_pts;
2345       cp->spn_ep = mpkt;
2346     }
2347     clpi_ep_fine *fp = new clpi_ep_fine();
2348     map->fine.append(fp);
2349     fp->is_angle_change_point = 0;
2350 // XXX - dont know what this is
2351     fp->i_end_position_offset = 1;
2352     fp->pts_ep = fine_pts;
2353     fp->spn_ep = pkt & 0x1ffff;
2354   }
2355   return 0;
2356 }
2357
2358 const AVRational media_info::clk45k = { 1, 45000 };
2359
2360 static int bd_stream_type(AVCodecID codec_id)
2361 {
2362   int stream_type = 0;
2363   switch (codec_id) {
2364   case AV_CODEC_ID_MPEG1VIDEO:
2365   case AV_CODEC_ID_MPEG2VIDEO:
2366     stream_type = BLURAY_STREAM_TYPE_VIDEO_MPEG2;
2367     break;
2368   case AV_CODEC_ID_H264:
2369     stream_type = BLURAY_STREAM_TYPE_VIDEO_H264;
2370     break;
2371   case AV_CODEC_ID_MP2:
2372   case AV_CODEC_ID_MP3:
2373     stream_type = BLURAY_STREAM_TYPE_AUDIO_MPEG1;
2374     break;
2375   case AV_CODEC_ID_AC3:
2376     stream_type = BLURAY_STREAM_TYPE_AUDIO_AC3;
2377     break;
2378   case AV_CODEC_ID_DTS:
2379     stream_type = BLURAY_STREAM_TYPE_AUDIO_DTS;
2380     break;
2381   case AV_CODEC_ID_TRUEHD:
2382     stream_type = BLURAY_STREAM_TYPE_AUDIO_TRUHD;
2383     break;
2384   default:
2385     fprintf(stderr, "unknown bluray stream type %s\n", avcodec_get_name(codec_id));
2386     exit(1);
2387   }
2388   return stream_type;
2389 }
2390
2391 static int bd_audio_format(int channels)
2392 {
2393   int audio_format = 0;
2394   switch( channels ) {
2395   case 1:
2396     audio_format = BLURAY_AUDIO_FORMAT_MONO;
2397     break;
2398   case 2:
2399     audio_format = BLURAY_AUDIO_FORMAT_STEREO;
2400     break;
2401   case 6:
2402     audio_format = BLURAY_AUDIO_FORMAT_MULTI_CHAN;
2403     break;
2404   default:
2405     fprintf(stderr, "unknown bluray audio format %d ch\n", channels);
2406     exit(1);
2407   }
2408   return audio_format;
2409 }
2410
2411 static int bd_audio_rate(int rate)
2412 {
2413   int audio_rate = 0;
2414   switch( rate ) {
2415   case 48000:  audio_rate = BLURAY_AUDIO_RATE_48;  break;
2416   case 96000:  audio_rate = BLURAY_AUDIO_RATE_96;  break;
2417   case 192000: audio_rate = BLURAY_AUDIO_RATE_192; break;
2418   default:
2419     fprintf(stderr, "unknown bluray audio rate %d\n", rate);
2420     exit(1);
2421   }
2422   return audio_rate;
2423 }
2424
2425 static int bd_video_format(int w, int h, int ilace)
2426 {
2427   if( w == 720 && h == 480 && ilace ) return BLURAY_VIDEO_FORMAT_480I;
2428   if( w == 720 && h == 576 && ilace ) return BLURAY_VIDEO_FORMAT_576I;
2429   if( w == 720 && h == 480 && !ilace ) return BLURAY_VIDEO_FORMAT_480P;
2430   if( w == 1920 && h == 1080 && ilace ) return BLURAY_VIDEO_FORMAT_1080I;
2431   if( w == 1280 && h == 720 && !ilace ) return BLURAY_VIDEO_FORMAT_720P;
2432   if( w == 1920 && h == 1080 && !ilace ) return BLURAY_VIDEO_FORMAT_1080P;
2433   if( w == 720 && h == 576 && !ilace ) return BLURAY_VIDEO_FORMAT_576P;
2434   fprintf(stderr, "unknown bluray video format %dx%d %silace\n",
2435     w, h, !ilace ? "not " : "");
2436   exit(1);
2437 }
2438
2439 static int bd_video_rate(double rate)
2440 {
2441   if( fabs(rate-23.976) < 0.01 ) return BLURAY_VIDEO_RATE_24000_1001;
2442   if( fabs(rate-24.000) < 0.01 ) return BLURAY_VIDEO_RATE_24;
2443   if( fabs(rate-25.000) < 0.01 ) return BLURAY_VIDEO_RATE_25;
2444   if( fabs(rate-29.970) < 0.01 ) return BLURAY_VIDEO_RATE_30000_1001;
2445   if( fabs(rate-50.000) < 0.01 ) return BLURAY_VIDEO_RATE_50;
2446   if( fabs(rate-59.940) < 0.01 ) return BLURAY_VIDEO_RATE_60000_1001;
2447   fprintf(stderr, "unknown bluray video framerate %5.2f\n",rate);
2448   exit(1);
2449 }
2450
2451 static int bd_aspect_ratio(int w, int h, double ratio)
2452 {
2453   double aspect = (w * ratio) / h;
2454   if( fabs(aspect-1.333) < 0.01 ) return BLURAY_ASPECT_RATIO_4_3;
2455   if( fabs(aspect-1.777) < 0.01 ) return BLURAY_ASPECT_RATIO_16_9;
2456   return w == 720 ? BLURAY_ASPECT_RATIO_4_3 : BLURAY_ASPECT_RATIO_16_9; 
2457   fprintf(stderr, "unknown bluray aspect ratio %5.3f\n",aspect);
2458   exit(1);
2459 }
2460
2461 int media_info::scan()
2462 {
2463   struct stat st;
2464   if( stat(filename, &st) ) return 1;
2465   file_size = st.st_size;
2466
2467   AVFormatContext *fmt_ctx = 0;
2468   AVDictionary *fopts = 0;
2469   av_dict_set(&fopts, "formatprobesize", "5000000", 0);
2470   av_dict_set(&fopts, "scan_all_pmts", "1", 0);
2471   av_dict_set(&fopts, "threads", "auto", 0);
2472   int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
2473   av_dict_free(&fopts);
2474   if( ret < 0 ) return ret;
2475   ret = avformat_find_stream_info(fmt_ctx, NULL);
2476
2477   bit_rate = fmt_ctx->bit_rate;
2478
2479   int ep_pid = -1;
2480   for( int i=0; ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
2481     AVStream *st = fmt_ctx->streams[i];
2482     AVMediaType type = st->codec->codec_type;
2483     switch( type ) {
2484     case AVMEDIA_TYPE_VIDEO: break;
2485     case AVMEDIA_TYPE_AUDIO: break;
2486     default: continue;
2487     }
2488     stream *s = new stream(type, i);
2489     s->pid = st->id;
2490     AVCodecID codec_id = st->codec->codec_id;
2491     switch( type ) {
2492     case AVMEDIA_TYPE_VIDEO: {
2493       if( ep_pid < 0 ) ep_pid = st->id;
2494       s->coding_type = bd_stream_type(codec_id);
2495       s->format = bd_video_format(st->codec->width, st->codec->height,
2496                 st->codec->flags & CODEC_FLAG_INTERLACED_ME);
2497       s->rate = bd_video_rate(!st->codec->framerate.den ? 0 :
2498                 (double)st->codec->framerate.num / st->codec->framerate.den);
2499       s->aspect = bd_aspect_ratio(st->codec->width, st->codec->height,
2500                 !st->sample_aspect_ratio.num || !st->sample_aspect_ratio.den ? 1. :
2501                  (double)st->sample_aspect_ratio.num / st->sample_aspect_ratio.den);
2502       break; }
2503     case AVMEDIA_TYPE_AUDIO: {
2504       s->coding_type = bd_stream_type(codec_id);
2505       s->format = bd_audio_format(st->codec->channels);
2506       s->rate = bd_audio_rate(st->codec->sample_rate);
2507       strcpy((char*)s->lang, "und");
2508       break; }
2509     default:
2510       break;
2511     }
2512     if( bit_rate > 0 && st->duration == AV_NOPTS_VALUE &&
2513         st->time_base.num < INT64_MAX / bit_rate ) {
2514       st->duration = av_rescale(8*file_size, st->time_base.den,
2515           bit_rate * (int64_t) st->time_base.num);
2516     }
2517     s->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2518     streams.append(s);
2519
2520     AVCodec *decoder = avcodec_find_decoder(codec_id);
2521     AVDictionary *copts = 0;
2522     ret = avcodec_open2(st->codec, decoder, &copts);
2523   }
2524   if( ep_pid < 0 )
2525     ep_pid = fmt_ctx->nb_streams > 0 ? fmt_ctx->streams[0]->id : 0;
2526
2527   int npgm = fmt_ctx->nb_programs;
2528   if( npgm < 1 ) {
2529     program *pgm = new program(-1, 1);
2530     pgm->ep_pid = ep_pid;
2531     pgm->pmt_pid = 0x1000;
2532     pgm->pcr_pid = 0x100;
2533     pgm->duration = 0;
2534     for( int jj=0; jj<streams.size(); ++jj ) {
2535       AVStream *st = fmt_ctx->streams[jj];
2536       AVMediaType type = st->codec->codec_type;
2537       switch( type ) {
2538       case AVMEDIA_TYPE_VIDEO:
2539       case AVMEDIA_TYPE_AUDIO:
2540         break;
2541       default:
2542         continue;
2543       }
2544       pgm->strm_idx.append(jj);
2545       if( pgm->duration < st->duration )
2546         pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2547     }
2548     programs.append(pgm);
2549   }
2550
2551   for( int ii=0; ii<npgm; ++ii ) {
2552     AVProgram *pgrm = fmt_ctx->programs[ii];
2553     program *pgm = new program(ii, pgrm->id);
2554     pgm->pmt_pid = pgrm->pmt_pid;
2555     pgm->pcr_pid = pgrm->pcr_pid;
2556     pgm->duration = 0;
2557     ep_pid = -1;
2558     for( int jj=0; jj<(int)pgrm->nb_stream_indexes; ++jj ) {
2559       int av_idx = pgrm->stream_index[jj];
2560       AVStream *st = fmt_ctx->streams[av_idx];
2561       AVMediaType type = st->codec->codec_type;
2562       switch( type ) {
2563       case AVMEDIA_TYPE_VIDEO:
2564         if( ep_pid < 0 ) ep_pid = st->id;
2565         break;
2566       case AVMEDIA_TYPE_AUDIO:
2567         break;
2568       default:
2569         continue;
2570       }
2571       int sidx = streams.size();
2572       while( --sidx>=0 && streams[sidx]->av_idx!=av_idx );
2573       if( sidx < 0 ) {
2574         fprintf(stderr, "bad stream idx %d in pgm %d\n",av_idx, ii);
2575         continue;
2576       }
2577       if( pgm->duration < st->duration )
2578         pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2579       pgm->strm_idx.append(sidx);
2580     }
2581     if( ep_pid < 0 ) {
2582       AVProgram *pgrm = fmt_ctx->programs[0];
2583       ep_pid = pgrm->nb_stream_indexes > 0 ?
2584           fmt_ctx->streams[pgrm->stream_index[0]]->id : 0;
2585     }
2586     pgm->ep_pid = ep_pid;
2587     programs.append(pgm);
2588   }
2589
2590   if( ret >= 0 )
2591     ret = scan(fmt_ctx);
2592
2593   for( int i=0; i<(int)fmt_ctx->nb_streams; ++i )
2594     avcodec_close(fmt_ctx->streams[i]->codec);
2595   avformat_close_input(&fmt_ctx);
2596
2597   return ret;
2598 }
2599
2600 int media_info::scan(AVFormatContext *fmt_ctx)
2601 {
2602   int ret = 0;
2603   AVPacket ipkt;
2604   av_init_packet(&ipkt);
2605
2606   for( int64_t count=0; ret>=0; ++count ) {
2607     av_packet_unref(&ipkt);
2608     ipkt.data = 0; ipkt.size = 0;
2609
2610     ret = av_read_frame(fmt_ctx, &ipkt);
2611     if( ret < 0 ) {
2612       if( ret == AVERROR_EOF ) break;
2613       ret = 0;
2614       continue;
2615     }
2616     if( !ipkt.data ) continue;
2617     if( (ipkt.flags & AV_PKT_FLAG_CORRUPT) ) continue;
2618     if( ipkt.pts == AV_NOPTS_VALUE ) continue;
2619     int i = ipkt.stream_index;
2620     if( i < 0 || i >= streams.size() ) continue;
2621
2622     stream *sp = 0;
2623     program *pgm = 0;
2624     for( int ii=0; !pgm && ii<programs.size(); ++ii ) {
2625       program *p = programs[ii];
2626       for( int jj=0; jj<p->strm_idx.size(); ++jj ) {
2627         sp = streams[p->strm_idx[jj]];
2628         if( sp->av_idx == i ) { pgm = p;  break; }
2629       }
2630     }
2631     if( !pgm ) continue;
2632     AVStream *st = fmt_ctx->streams[i];
2633     if( pgm->ep_pid != st->id ) continue;
2634     int64_t pts45k = av_rescale_q(ipkt.pts, st->time_base, clk45k);
2635     if( sp->start_pts > pts45k ) sp->start_pts = pts45k;
2636     if( sp->end_pts < pts45k ) sp->end_pts = pts45k;
2637     if( pgm->start_time > pts45k ) pgm->start_time = pts45k;
2638     if( pgm->end_time < pts45k ) pgm->end_time = pts45k;
2639
2640     if( !(ipkt.flags & AV_PKT_FLAG_KEY) ) continue;
2641
2642     if( sp->last_pts != pts45k ) {
2643       sp->last_pts = pts45k;
2644       pgm->add_label(count, ipkt.pos, pts45k, st->id);
2645     }
2646   }
2647
2648   for( int ii=0; ii<programs.size(); ++ii ) {
2649     program *pgm = programs[ii];
2650     if( pgm->end_time > pgm->start_time )
2651       pgm->duration = pgm->end_time - pgm->start_time;
2652   }
2653
2654   return ret != AVERROR_EOF ? -1 : 0;
2655 }
2656
2657 int
2658 Media::compose()
2659 {
2660 // index
2661   bs.init();
2662   idx.sig = 1;
2663   idx.first_play.set_hdmv(0, pb_typ_movie);
2664   idx.top_menu.set_hdmv(0xffff, pb_typ_iactv);
2665
2666 // movie
2667   bs.init();
2668   mov.sig = 1;
2669   movie_obj *mp = new movie_obj();
2670   mp->resume_intention_flag = 1;
2671   command_obj *cmd = new command_obj();
2672   cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
2673   mp->cmds.append(cmd);  // JUMP_TITLE 1
2674   cmd = new command_obj();
2675   cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2676   mp->cmds.append(cmd);
2677   mov.movies.append(mp); // BREAK
2678
2679   
2680   for( int ii=0; ii<size(); ++ii ) {
2681     mp = new movie_obj();
2682     mp->resume_intention_flag = 1;
2683     cmd = new command_obj();
2684     cmd->cmd = htobe32(0x22800000); cmd->dst = ii; cmd->src = 0;
2685     mp->cmds.append(cmd);  // PLAY_PL   ii
2686     cmd = new command_obj();
2687     cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2688     mp->cmds.append(cmd);
2689     mov.movies.append(mp); // BREAK
2690   }
2691
2692   mp = new movie_obj();
2693   mp->resume_intention_flag = 1;
2694   cmd = new command_obj();
2695   cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
2696   mp->cmds.append(cmd);  // JUMP_TITLE 1
2697   cmd = new command_obj();
2698   cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2699   mp->cmds.append(cmd);
2700   mov.movies.append(mp); // BREAK
2701
2702   title_obj *tp = 0;
2703 // clips
2704   for( int ii=0; ii<size(); ++ii ) {
2705     if( !tp ) {
2706       tp = new title_obj();
2707       tp->set_hdmv(idx.titles.size()+1, pb_typ_movie);
2708       idx.titles.append(tp);
2709     }
2710     bs.init();
2711     media_info *ip = get(ii);
2712 // clip program, if specified
2713     int pidx = ip->programs.size();
2714     while( --pidx>=0 && ip->programs[pidx]->pid != ip->pgm_pid );
2715     if( pidx < 0 ) pidx = 0;
2716     ip->pidx = pidx;
2717     ip->pgm_pid = ip->prog()->pid;
2718
2719     clpi_cl *cp = new clpi_cl();
2720     cp->clip.clip_stream_type = 1;
2721     cp->clip.application_type = BLURAY_APP_TYPE_MAIN_MOVIE;
2722     cp->clip.ts_recording_rate = ip->bit_rate;
2723     uint32_t ts_pkt_count = ip->file_size / BLURAY_TS_PKTSZ + 1;
2724     cp->clip.num_source_packets = ts_pkt_count;
2725     cp->clip.ts_type_info.validity = 0x80;
2726     strcpy(cp->clip.ts_type_info.format_id, "HDMV");
2727     cp->cpi.type = 1;
2728
2729     for( int jj=0; jj<ip->programs.size(); ++jj ) {
2730       program *pgm = ip->programs[jj];
2731       clpi_prog *p = new clpi_prog(pgm->pmt_pid);
2732       for( int kk=0; kk<pgm->strm_idx.size(); ++kk ) {
2733         int k = pgm->strm_idx[kk];
2734         stream *sp = ip->streams[k];
2735         clpi_prog_stream *s = new clpi_prog_stream();
2736         s->pid = sp->pid;
2737         s->coding_type = sp->coding_type;
2738         s->format = sp->format;
2739 //use unspecified (0)
2740 //      if( !idx.video_format ) idx.video_format = s->format;
2741         s->rate = sp->rate;
2742 //      if( !idx.frame_rate ) idx.frame_rate = s->rate;
2743         switch( sp->type ) {
2744         case AVMEDIA_TYPE_VIDEO:
2745           s->aspect = sp->aspect;
2746           break;
2747         case AVMEDIA_TYPE_AUDIO:
2748           memcpy(s->lang,sp->lang,sizeof(s->lang));
2749           break;
2750         default:
2751           break;
2752         }
2753         p->streams.append(s);
2754       }
2755       clpi_ep_map_entry *map = new clpi_ep_map_entry(pgm->ep_pid);
2756       pgm->build_toc(map);
2757       cp->cpi.append(map);
2758       cp->programs.append(p);
2759
2760       clpi_atc_seq *atc_seq = new clpi_atc_seq();
2761       clpi_stc_seq *stc_seq = new clpi_stc_seq();
2762       stc_seq->pcr_pid = pgm->pcr_pid;
2763       stc_seq->presentation_start_time = pgm->start_time;
2764       stc_seq->presentation_end_time = pgm->end_time;
2765       atc_seq->stc_seq.append(stc_seq);
2766       cp->sequences.append(atc_seq);
2767     }
2768
2769     cl.append(cp);
2770     tp->last = ii;
2771     if( ip->brk ) tp = 0;
2772   }
2773
2774 // playlists, one per title
2775 //   one playitem per media clip
2776   int clip_id = 0;
2777   for( int ii=0; ii<idx.titles.size(); ++ii ) {
2778     bs.init();
2779     media_info *ip = get(clip_id);
2780     program *pgm = ip->prog();
2781     mpls_pl *pp = new mpls_pl();
2782     pp->app_info.playback_type = BLURAY_PLAYBACK_TYPE_SEQUENTIAL;
2783 //  pp->app_info.uo_mask.xxx = 1;
2784     int last = idx.titles[ii]->last;
2785     for( ; clip_id<=last; ++clip_id ) {
2786       ip = get(clip_id);
2787       pgm = ip->prog();
2788       mpls_pi *pi = new mpls_pi();
2789       pi->connection_condition = 1; // seamless
2790       pi->in_time = pgm->start_time;
2791       pi->out_time = pgm->end_time;
2792       if( ip->still )
2793         pi->still_mode = BLURAY_STILL_INFINITE;
2794       int64_t end_time = pgm->start_time + pgm->duration;
2795       if( pi->out_time < end_time ) pi->out_time = end_time;
2796       mpls_clip *cp = new mpls_clip();
2797       sprintf(cp->clip_id,"%05d", clip_id);
2798       pi->clip.append(cp);
2799       for( int kk=0; kk<ip->streams.size(); ++kk ) {
2800         stream *sp = ip->streams[kk];
2801         switch( sp->type ) {
2802         case AVMEDIA_TYPE_VIDEO: break;
2803         case AVMEDIA_TYPE_AUDIO: break;
2804         default: continue;
2805         }
2806         mpls_stream *ps = new mpls_stream();
2807         ps->pid = sp->pid;
2808         ps->stream_type = BLURAY_PG_TEXTST_STREAM;
2809         ps->coding_type = sp->coding_type;
2810         ps->format = sp->format;
2811         ps->rate = sp->rate;
2812         switch( sp->type ) {
2813         case AVMEDIA_TYPE_VIDEO:
2814           pi->stn.video.append(ps);
2815           break;
2816         case AVMEDIA_TYPE_AUDIO:
2817           memcpy(ps->lang, sp->lang, sizeof(ps->lang));
2818           pi->stn.audio.append(ps);
2819           break;
2820         default:
2821           break;
2822         }
2823       }
2824       pp->play_item.append(pi);
2825     }
2826 // chapter marks every ch_duration ticks
2827     int64_t ch_duration = 45000 * 60*10;
2828     int64_t mrktm = ch_duration;
2829     int64_t plytm = 0;
2830     int pmark = 0, pitem = 0;
2831     mpls_pi *pi = pp->play_item[pitem];
2832     mpls_plm *pm = new mpls_plm();
2833     pm->mark_id = pmark++;
2834     pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2835     pm->play_item_ref = pitem;
2836     pm->time = pi->in_time;
2837     pm->entry_es_pid = 0;
2838     pp->play_mark.append(pm);
2839     for( int jj=0; jj < pp->play_item.size(); ++jj ) {
2840       pitem = jj;
2841       pi = pp->play_item[pitem];
2842       int64_t pi_duration = pi->out_time - pi->in_time;
2843       int64_t endtm = plytm + pi_duration;
2844       while( mrktm < endtm ) {
2845         pm = new mpls_plm();
2846         pm->mark_id = pmark++;
2847         pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2848         pm->play_item_ref = pitem;
2849         pm->time = pi->in_time + mrktm - plytm;
2850         pm->entry_es_pid = 0;
2851         pp->play_mark.append(pm);
2852         mrktm += ch_duration;
2853       }
2854       plytm = endtm;
2855     }
2856     pm = new mpls_plm();
2857     pm->mark_id = pmark;
2858     pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2859     pm->play_item_ref = pitem;
2860     pm->time = pi->out_time;
2861     pm->entry_es_pid = 0;
2862     pp->play_mark.append(pm);
2863
2864     pl.append(pp);
2865   }
2866   return 0;
2867 }
2868
2869 int Media::
2870 bd_path(const char *bp, const char *fmt, va_list ap)
2871 {
2872   int n = sizeof(filename)-1;
2873   char *cp = filename;
2874   const char *pp = path;
2875   while( n>0 && (*cp=*pp)!=0 ) { --n;  ++cp;  ++pp; }
2876   while( n>0 && (*cp=*bp)!=0 ) { --n;  ++cp;  ++bp; }
2877   n -= vsnprintf(cp, n, fmt, ap);
2878   va_end(ap);
2879   return n > 0 ? 0 : 1;
2880 }
2881
2882 int Media::
2883 bd_copy(const char *ifn, const char *fmt, ...)
2884 {
2885   int n, ret = 1;
2886   char bfr[0x40000];
2887   FILE *ifp = fopen(ifn,"r");
2888   if( ifp ) {
2889     va_list ap;
2890     va_start(ap, fmt);
2891     if( bd_path("/BDMV/", fmt, ap) ) return 1;
2892     va_end(ap);
2893     FILE *ofp = fopen(filename,"w");
2894     if( ofp ) {
2895       setvbuf(ifp, 0, _IOFBF, 0x80000);
2896       setvbuf(ofp, 0, _IOFBF, 0x80000);
2897       while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
2898       fclose(ofp);
2899       ret = 0;
2900     }
2901     fclose(ifp);
2902   }
2903   if( ret )
2904     fprintf(stderr, "cant copy clip %s\n",ifn);
2905   return ret;
2906 }
2907
2908 int Media::
2909 bd_open(const char *fmt, ...)
2910 {
2911   bs.init();
2912   if( !path ) return 0;
2913   va_list ap;
2914   va_start(ap, fmt);
2915   if( bd_path("/BDMV/", fmt, ap) ) return 1;
2916   va_end(ap);
2917   if( bs.open(filename) ) {
2918     fprintf(stderr, "cant open file %s\n",filename);
2919     return 1;
2920   }
2921   return 0;
2922 }
2923
2924 int Media::
2925 bd_backup(const char *fmt, ...)
2926 {
2927   bs.close();
2928   if( !path ) return 0;
2929   int n, ret = 1;
2930   char bfr[0x10000];
2931   FILE *ifp = fopen(filename,"r");
2932   if( ifp ) {
2933     va_list ap;
2934     va_start(ap, fmt);
2935     if( bd_path("/BDMV/BACKUP/", fmt, ap) ) return 1;
2936     va_end(ap);
2937     FILE *ofp = fopen(filename,"w");
2938     if( ofp ) {
2939       while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
2940       fclose(ofp);
2941       ret = 0;
2942     }
2943     fclose(ifp);
2944   }
2945   if( ret )
2946     fprintf(stderr, "cant backup %s\n",filename);
2947   return ret;
2948 }
2949
2950 int Media::write(char *fn)
2951 {
2952   this->path = fn;
2953 // index
2954   if( bd_open("index.bdmv") ) return 1;
2955   if( idx.write() ) return 1;
2956   if( bd_backup("index.bdmv") ) return 1;
2957 // movie
2958   if( bd_open("MovieObject.bdmv") ) return 1;
2959   if( mov.write() ) return 1;
2960   if( bd_backup("MovieObject.bdmv") ) return 1;
2961 // clips
2962   for( int ii=0; ii<cl.size(); ++ii ) {
2963     if( bd_open("CLIPINF/%05d.clpi", ii) ) return 1;
2964     if( cl[ii]->write() ) return 1;
2965     if( bd_backup("CLIPINF/%05d.clpi", ii) ) return 1;
2966   }
2967 // playlists
2968   for( int ii=0; ii<pl.size(); ++ii ) {
2969     if( bd_open("PLAYLIST/%05d.mpls", ii) ) return 1;
2970     if( pl[ii]->write() ) return 1;
2971     if( bd_backup("PLAYLIST/%05d.mpls", ii) ) return 1;
2972   }
2973   return 0;
2974 }
2975
2976 int
2977 main(int ac, char **av)
2978 {
2979   char *path = av[1];
2980   if( mkbdmv(path) ) return 1;
2981   av_register_all();
2982   av_log_set_level(AV_LOG_FATAL);
2983   //av_log_set_level(AV_LOG_VERBOSE);
2984   //av_log_set_level(AV_LOG_DEBUG);
2985   Media media;
2986   media_info *mp = 0;
2987
2988   for( int ii=2; ii<ac; ++ii ) {
2989     char *ap = av[ii];
2990     // any dash seq followed by number sets curr title pgm_pid
2991     // single dash only sets title pgm_pid
2992     // double dash ends curr title, starts a new title
2993     // triple dash ends curr title as infinite still
2994     if( *ap == '-' ) {
2995       if( !mp ) continue;
2996       if( *++ap == '-' ) {
2997         mp->brk = 1;
2998         if( *++ap == '-' ) { ++ap;  mp->still = 1; }
2999       }
3000       if( *ap >= '0' && *ap <= '9' )
3001         mp->pgm_pid = strtoul(ap,&ap,0);
3002       if( mp->brk ) mp = 0;
3003       if( !ap || *ap ) {
3004         fprintf(stderr, "err arg %d: %s\n",ii,av[ii]);
3005         return 1;
3006       }
3007       continue;
3008     }
3009     mp = new media_info(av[ii]);
3010     media.append(mp);
3011     if( mp->scan() ) {
3012       fprintf(stderr, "cant scan media: %s\n", av[ii]);
3013       return 1;
3014     }
3015   }
3016
3017   if( mp ) mp->brk = 1;
3018
3019   if( media.compose() ) {
3020     fprintf(stderr, "cant compose media\n");
3021     return 1;
3022   }
3023   if( media.write(0) ) {
3024     fprintf(stderr, "cant prepare media\n");
3025     return 1;
3026   }
3027   if( media.write(path) ) {
3028     fprintf(stderr, "cant write media\n");
3029     return 1;
3030   }
3031
3032   for( int ii=0; ii<media.size(); ++ii )
3033     if( media.bd_copy(media[ii]->filename, "STREAM/%05d.m2ts", ii) )
3034       return 1;
3035
3036   return 0;
3037 }
3038