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