a85967062f763cd0130f6d8e55372b355cc70e7e
[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   int64_t start_pts;
1114   int64_t end_pts;
1115   int64_t last_pts;
1116   int64_t duration;
1117
1118   stream(AVMediaType ty, int i) {
1119     type = ty;  av_idx = i;
1120     start_pts = INT64_MAX; end_pts = INT64_MIN;
1121     last_pts = -1;
1122   }
1123   ~stream() {}
1124 };
1125
1126 class mark {
1127 public:
1128   static int cmpr(mark **, mark **);
1129   int64_t sample, pos, pts;
1130   uint32_t pkt, pid;
1131   mark(int64_t s, int64_t p, int64_t ts, uint32_t pk, int id) {
1132     sample = s;  pos = p;  pts = ts; pkt = pk;  pid = id;
1133   }
1134 };
1135
1136 int mark::cmpr(mark **a, mark **b)
1137 {
1138   mark *ap = *(mark **)a,  *bp = *(mark **)b;
1139   return ap->pts > bp->pts ? 1 : ap->pts < bp->pts ? -1 : 0;
1140 }
1141
1142 class _program {
1143 public:
1144   int pmt_pid, pcr_pid, ep_pid;
1145   int64_t start_time, end_time;
1146   int64_t duration;
1147   _program() {
1148     memset(this, 0, sizeof(*this));
1149     start_time = INT64_MAX; end_time = INT64_MIN;
1150   }
1151   ~_program() {}
1152 };
1153
1154 class program : public _program {
1155 public:
1156   int idx;
1157   uint16_t pid;
1158   ArrayList<int> strm_idx;
1159   ArrayList<mark*> marks;
1160   int64_t curr_pos;
1161   int build_toc(clpi_ep_map_entry *map);
1162   void add_label(uint32_t pk, int64_t p, int64_t ts, int id) {
1163     marks.append(new mark(curr_pos, p, ts, pk, id));
1164   }
1165
1166   program(int i, int id) { idx = i;  pid = id;  curr_pos = 0; }
1167   ~program() { marks.remove_all_objects(); }
1168 };
1169
1170 class _media_info {
1171 public:
1172   int bit_rate;
1173   int64_t file_size;
1174
1175   _media_info() {
1176     memset(this, 0, sizeof(*this));
1177   }
1178   ~_media_info() {}
1179 };
1180
1181 class media_info : public _media_info {
1182 public:
1183   static const AVRational clk45k;
1184   char filename[BCTEXTLEN];
1185   int pgm_pid;
1186   int brk, pidx, still;
1187   ArrayList<stream *> streams;
1188   ArrayList<program *> programs;
1189   program *prog()  { return programs[pidx]; }
1190
1191   media_info(const char *fn) {
1192     strcpy(filename, fn);
1193     brk = 0;  pidx = 0;  pgm_pid = -1;  still = 0;
1194   }
1195   ~media_info() {
1196     streams.remove_all_objects();
1197     programs.remove_all_objects();
1198   }
1199
1200   int scan();
1201   int scan(AVFormatContext *fmt_ctx);
1202 };
1203
1204 class Media : public ArrayList<media_info *> {
1205 public:
1206   char *path;
1207   char filename[BCTEXTLEN];
1208   int bd_path(const char *bp, const char *fmt, va_list ap);
1209   int bd_open(const char *fmt, ...);
1210   int bd_backup(const char *fmt, ...);
1211   int bd_copy(const char *ifn, const char *fmt, ...);
1212
1213   index_file idx;
1214   movie_file mov;
1215   ArrayList<clpi_cl *> cl;
1216   ArrayList<mpls_pl *> pl;
1217
1218   void add_movie(uint32_t *ops, int n);
1219   int compose();
1220   int write(char *fn);
1221
1222   Media() { path = 0;  filename[0] = 0; }
1223   ~Media() {
1224     remove_all_objects();
1225     cl.remove_all_objects();
1226     pl.remove_all_objects();
1227   }
1228 };
1229
1230 #endif
1231
1232 void bs_file::init()
1233 {
1234   fp = 0;
1235   reg = len = 0;
1236   fpos = fsz = 0;
1237 }
1238
1239 int
1240 bs_file::open(const char *fn)
1241 {
1242   fp = fopen(fn,"w");
1243   if( !fp ) perror(fn);
1244   return fp != 0 ? 0 : 1;
1245 }
1246
1247 void
1248 bs_file::close()
1249 {
1250   if( fp ) { fclose(fp); fp = 0; }
1251 }
1252
1253 void
1254 bs_file::write(uint32_t v, int n)
1255 {
1256   uint64_t vv = reg;
1257   vv <<= n;  vv |= v;
1258   reg = vv;  len += n;
1259   while( len >= 8 ) {
1260     len -= 8;
1261     if( fp ) fputc((vv >> len), fp);
1262     if( ++fpos > fsz ) fsz = fpos;
1263   }
1264 }
1265
1266 void
1267 bs_file::writeb(uint8_t * bp, int n)
1268 {
1269   while( --n >= 0 ) write(*bp++, 8);
1270 }
1271
1272 void
1273 bs_file::pad(int n)
1274 {
1275   while( n > 32 ) { write(0, 32);  n -= 32; }
1276   if( n > 0 ) write(0, n);
1277 }
1278
1279 void
1280 bs_file::posb(int64_t n)
1281 {
1282   if( fpos == fsz && n > fpos ) {
1283     padb(n-fpos);
1284     return;
1285   }
1286   fpos = n;
1287   if( fp ) fseek(fp, fpos, SEEK_SET);
1288 }
1289
1290 static bs_file bs;
1291
1292
1293 int
1294 movie_file::write()
1295 {
1296   // output header
1297   bs.writeb("MOBJ", 4);
1298   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1299   int movie_start = 0x0028;
1300   bs.posb(movie_start);
1301   bs_len(bs, 32);
1302   bs.write(0, 32);
1303   bs.write(movies.size(), 16);
1304
1305   for (int i = 0; i < movies.size(); ++i) {
1306     movie_obj *mov = movies[i];
1307     bs.write(mov->resume_intention_flag, 1);
1308     bs.write(mov->menu_call_mask, 1);
1309     bs.write(mov->title_search_mask, 1);
1310     bs.write(0, 13);
1311     ArrayList<command_obj *> &cmds = mov->cmds;
1312     int num_cmds = cmds.size();
1313     bs.write(num_cmds, 16);
1314     for (int j = 0; j < num_cmds; ++j) {
1315       command_obj *cmd = cmds[j];
1316       bs.write(cmd->op_cnt, 3);
1317       bs.write(cmd->grp, 2);
1318       bs.write(cmd->sub_grp, 3);
1319       bs.write(cmd->imm_op1, 1);
1320       bs.write(cmd->imm_op2, 1);
1321       bs.write(0, 2);
1322       bs.write(cmd->branch_opt, 4);
1323       bs.write(0, 4);
1324       bs.write(cmd->cmp_opt, 4);
1325       bs.write(0, 3);
1326       bs.write(cmd->set_opt, 5);
1327       //bs.write(cmd->cmd, 32);
1328       bs.write(cmd->dst, 32);
1329       bs.write(cmd->src, 32);
1330     }
1331   }
1332 //in sony AVCHD
1333 //  bs.write('l', 8);
1334 //  bs.writebcd(year, 16);
1335 //  bs.writebcd(month, 8);
1336 //  bs.writebcd(day, 8);
1337 //  bs.writebcd(hour, 8);
1338 //  bs.writebcd(min, 8);
1339 //  bs.writebcd(sec, 8);
1340   bs_end(bs);
1341   return 0;
1342 }
1343
1344 void
1345 pb_obj::set_hdmv(int id, int pt)
1346 {
1347   obj_typ = obj_hdmv;
1348   pb_typ = pt;
1349   delete [] bdj_name;
1350   bdj_name = 0;
1351   hdmv_id = id;
1352 }
1353
1354 void
1355 pb_obj::set_bdj(char *nm, int pt)
1356 {
1357   obj_typ = obj_bdj;
1358   pb_typ = pt;
1359   delete [] bdj_name;
1360   bdj_name = 0;
1361   bdj_name = cstrdup(nm);
1362 }
1363
1364 void
1365 pb_obj::write_hdmv_obj(int id_ref)
1366 {
1367   bs.write(pb_typ, 2);
1368   bs.write(0, 14);
1369   bs.write(id_ref, 16);
1370   bs.write(0, 32);
1371 }
1372
1373 void
1374 pb_obj::write_bdj_obj(char *name)
1375 {
1376   bs.write(pb_typ, 2);
1377   bs.write(0, 14);
1378   bs.writeb(name, 5);
1379   bs.write(0, 8);
1380 }
1381
1382 void
1383 pb_obj::write_obj()
1384 {
1385   switch (obj_typ) {
1386   case obj_bdj:
1387     write_bdj_obj(bdj_name);
1388     break;
1389   case obj_hdmv:
1390   default:
1391     write_hdmv_obj(hdmv_id);
1392     break;
1393   }
1394 }
1395
1396 void
1397 title_obj::write_obj()
1398 {
1399   bs.write(obj_typ, 2);
1400   bs.write(acc_typ, 2);
1401   bs.write(0, 28);
1402   pb_obj::write_obj();
1403 }
1404
1405
1406 void
1407 index_file::write_pb_obj(pb_obj * pb)
1408 {
1409   bs.write(pb->obj_typ, 2);
1410   bs.write(0, 30);
1411   pb->write_obj();
1412 }
1413
1414 int
1415 index_file::write()
1416 {
1417   // output header
1418   bs.writeb("INDX", 4);
1419   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1420   bs_ofs(bs, 32);
1421   exten.bs_zofs(bs, 32);
1422   int appinfo_start = 0x28;
1423   bs.posb(appinfo_start);
1424   appinf.bs_len(bs, 32);
1425   bs.write(1, 1);
1426   bs.write(initial_output_mode_preference, 1);
1427   bs.write(content_exist_flag, 1);
1428   bs.write(0, 5);
1429   bs.write(video_format, 4);
1430   bs.write(frame_rate, 4);
1431   bs.writeb(user_data, 32);
1432   appinf.bs_end(bs);
1433
1434   // output index
1435   bs_len(bs, 32);
1436   write_pb_obj(&first_play);
1437   write_pb_obj(&top_menu);
1438   bs.write(titles.size(), 16);
1439
1440   for (int i = 0; i < titles.size(); ++i)
1441     titles[i]->write_obj();
1442   bs_end(bs);
1443   exten.bs_len(bs,32);
1444   exten.bs_end(bs);
1445   return 0;
1446 }
1447
1448
1449
1450 int
1451 bdid::write()
1452 {
1453   bs.writeb("BDID",4);
1454   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1455   bs.write(data_start, 32);
1456   bs.write(extension_data_start, 32);
1457   bs.posb(40 - 16);
1458   bs.writeb(org_id, sizeof(org_id));
1459   bs.writeb(disc_id, sizeof(disc_id));
1460   return 0;
1461 }
1462
1463 // XXX - not current referenced
1464 #if 0
1465 int
1466 bdmv_write_extension_data(int start_address,
1467         int (*handler) (int, int, void *), void *handle)
1468 {
1469   int64_t length;
1470   int num_entries, n;
1471
1472   bs.write(length, 32);   /* length of extension data block */
1473   if( length < 1 )
1474     return 1;
1475
1476   bs.pad(32);             /* relative start address of extension data */
1477   bs.pad(24);             /* padding */
1478   bs.write(num_entries, 8);
1479
1480   for (n = 0; n < num_entries; n++) {
1481     bs.write(id1, 16);
1482     bs.write(id2, 16);
1483     bs.write(ext_start, 32);
1484     bs.write(ext_len, 32);
1485     saved_pos = bs.pos() >> 3;
1486     bs.posb(start_address + ext_start);
1487     handler(id1, id2, handle);
1488     bs.posb(saved_pos);
1489   }
1490
1491   return 0;
1492 }
1493 #endif
1494
1495 int
1496 clpi_prog_stream::write()
1497 {
1498   bs.write(pid, 16);
1499   bs_len(bs, 8);
1500
1501   bs.write(coding_type, 8);
1502   switch (coding_type) {
1503   case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1504   case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1505   case BLURAY_STREAM_TYPE_VIDEO_VC1:
1506   case BLURAY_STREAM_TYPE_VIDEO_H264:
1507   case 0x20:
1508     bs.write(format, 4);
1509     bs.write(rate, 4);
1510     bs.write(aspect, 4);
1511     bs.pad(2);
1512     bs.write(oc_flag, 1);
1513     bs.pad(1);
1514     break;
1515
1516   case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1517   case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1518   case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1519   case BLURAY_STREAM_TYPE_AUDIO_AC3:
1520   case BLURAY_STREAM_TYPE_AUDIO_DTS:
1521   case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1522   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1523   case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1524   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1525   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1526   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1527     bs.write(format, 4);
1528     bs.write(rate, 4);
1529     bs.writeb(lang, 3);
1530     break;
1531
1532   case BLURAY_STREAM_TYPE_SUB_PG:
1533   case BLURAY_STREAM_TYPE_SUB_IG:
1534   case 0xa0:
1535     bs.writeb(lang, 3);
1536     break;
1537
1538   case BLURAY_STREAM_TYPE_SUB_TEXT:
1539     bs.write(char_code, 8);
1540     bs.writeb(lang, 3);
1541     break;
1542
1543   default:
1544     fprintf(stderr, "clpi_prog_stream: unrecognized coding type %02x\n",
1545             coding_type);
1546     return 1;
1547   };
1548
1549   bs.padb(0x15 - bs_posb(bs));
1550   bs_end(bs);
1551   return 0;
1552 }
1553
1554 int
1555 clpi_cl::write_header()
1556 {
1557   bs.writeb("HDMV", 4);
1558   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1559   bs.write(sequence_info_start_addr, 32);
1560   bs.write(program_info_start_addr, 32);
1561   bs.write(cpi_start_addr, 32);
1562   bs.write(clip_mark_start_addr, 32);
1563   bs.write(ext_data_start_addr, 32);
1564   return 0;
1565 }
1566
1567 int
1568 clpi_atc_delta::write()
1569 {
1570   bs.write(delta, 32);
1571   bs.writeb(file_id, 5);
1572   bs.writeb(file_code, 4);
1573   bs.pad(8);
1574   return 0;
1575 }
1576
1577 int
1578 clpi_clip_info::write()
1579 {
1580   bs.posb(40);
1581   bs_len(bs, 32);
1582
1583   bs.pad(16);                   // reserved
1584   bs.write(clip_stream_type, 8);
1585   bs.write(application_type, 8);
1586   bs.pad(31);                   // skip reserved 31 bits
1587   bs.write(is_atc_delta, 1);
1588   bs.write(ts_recording_rate, 32);
1589   bs.write(num_source_packets, 32);
1590
1591   bs.padb(128);                 // Skip reserved 128 bytes
1592
1593   // ts type info block
1594   int ts_len = 30;
1595   bs.write(ts_len, 16);
1596   int64_t pos = bs.posb();
1597   if( ts_len ) {
1598     bs.write(ts_type_info.validity, 8);
1599     bs.writeb(ts_type_info.format_id, 4);
1600     // pad the stuff we don't know anything about
1601     bs.padb(ts_len - (bs.posb() - pos));
1602   }
1603
1604   if( is_atc_delta ) {
1605     bs.pad(8);                  // Skip reserved byte
1606     bs.write(atc_delta.size(), 8);
1607     for( int ii=0; ii < atc_delta.size(); ++ii )
1608       if( atc_delta[ii]->write() ) return 1;
1609   }
1610
1611   // font info
1612   if( application_type == 6 /* Sub TS for a sub-path of Text subtitle */  ) {
1613     bs.pad(8);
1614     bs.write(font_info.font.size(), 8);
1615     if( font_info.font.size() ) {
1616       for( int ii=0; ii < font_info.font.size(); ++ii ) {
1617         bs.writeb(font_info.font[ii]->file_id, 5);
1618         bs.pad(8);
1619       }
1620     }
1621   }
1622
1623   bs_end(bs);
1624   return 0;
1625 }
1626
1627 int
1628 clpi_stc_seq::write()
1629 {
1630   bs.write(pcr_pid, 16);
1631   bs.write(spn_stc_start, 32);
1632   bs.write(presentation_start_time, 32);
1633   bs.write(presentation_end_time, 32);
1634   return 0;
1635 }
1636
1637 int
1638 clpi_atc_seq::write()
1639 {
1640   bs.write(spn_atc_start, 32);
1641   bs.write(stc_seq.size(), 8);
1642   bs.write(offset_stc_id, 8);
1643
1644   for( int ii=0; ii < stc_seq.size(); ++ii )
1645     if( stc_seq[ii]->write() ) return 1;
1646   return 0;
1647 }
1648
1649 int
1650 clpi_sequences::write()
1651 {
1652   bs_len(bs, 32);
1653   bs.padb(1);                   // reserved byte
1654   bs.write(size(), 8);
1655   for( int ii=0; ii < size(); ++ii )
1656     if( get(ii)->write() ) return 1;
1657   bs_end(bs);
1658   return 0;
1659 }
1660
1661 int
1662 clpi_prog::write()
1663 {
1664   bs.write(spn_program_sequence_start, 32);
1665   bs.write(program_map_pid, 16);
1666   bs.write(streams.size(), 8);
1667   bs.write(num_groups, 8);
1668   for( int ii=0; ii < streams.size(); ++ii )
1669     if( streams[ii]->write() ) return 1;
1670   return 0;
1671 }
1672
1673 int
1674 clpi_programs::write()
1675 {
1676   bs_len(bs, 32);
1677   bs.padb(1);                   // reserved byte
1678   bs.write(size(), 8);
1679   for( int ii=0; ii < size(); ++ii )
1680     if( get(ii)->write() ) return 1;
1681   bs_end(bs);
1682   return 0;
1683 }
1684
1685 int
1686 clpi_ep_coarse::write()
1687 {
1688   bs.write(ref_ep_fine_id, 18);
1689   bs.write(pts_ep, 14);
1690   bs.write(spn_ep, 32);
1691   return 0;
1692 }
1693
1694 int
1695 clpi_ep_fine::write()
1696 {
1697   bs.write(is_angle_change_point, 1);
1698   bs.write(i_end_position_offset, 3);
1699   bs.write(pts_ep, 11);
1700   bs.write(spn_ep, 17);
1701   return 0;
1702 }
1703
1704 int
1705 clpi_ep_map_entry::write(uint32_t ep_map_pos)
1706 {
1707   bs.write(pid, 16);
1708   bs.pad(10);
1709   bs.write(ep_stream_type, 4);
1710   bs.write(coarse.size(), 16);
1711   bs.write(fine.size(), 18);
1712   bs.write(ep_map_stream_start_addr - ep_map_pos, 32);
1713   return 0;
1714 }
1715
1716 int
1717 clpi_ep_map_entry::write_map()
1718 {
1719   ep_map_stream_start_addr = bs.posb();
1720   bs.write(fine_start, 32);
1721
1722   for( int ii=0; ii < coarse.size(); ++ii )
1723     if( coarse[ii]->write() ) return 1;
1724
1725   fine_start = bs.posb() - ep_map_stream_start_addr;
1726   for( int ii=0; ii < fine.size(); ++ii )
1727     if( fine[ii]->write() ) return 1;
1728
1729   return 0;
1730 }
1731
1732 int
1733 clpi_cpi::write()
1734 {
1735   bs_len(bs, 32);
1736   bs.pad(12);
1737   bs.write(type, 4);
1738   uint32_t ep_map_pos = bs.posb();
1739
1740   // EP Map starts here
1741   bs.pad(8);
1742   bs.write(size(), 8);
1743
1744   for( int ii=0; ii < size(); ++ii )
1745     if( get(ii)->write(ep_map_pos) ) return 1;
1746
1747   for( int ii=0; ii < size(); ++ii )
1748     if( get(ii)->write_map() ) return 1;
1749
1750   bs_end(bs);
1751   return 0;
1752 }
1753
1754 int
1755 clpi_cmrk::write()
1756 {
1757   bs_len(bs, 32);
1758   bs_end(bs);
1759   return 0;
1760 }
1761
1762 int
1763 clpi_extents::write()
1764 {
1765   bs_len(bs, 32);
1766   bs.write(size(), 32);
1767   for( int ii=0; ii < size(); ++ii )
1768     bs.write(get(ii), 32);
1769   return 0;
1770 }
1771
1772 int
1773 clpi_cl::write_clpi_extension(int id1, int id2, void *handle)
1774 {
1775   clpi_cl *cl = (clpi_cl *) handle;
1776
1777   if( id1 == 1 ) {
1778     if( id2 == 2 ) {
1779       // LPCM down mix coefficient
1780       //write_lpcm_down_mix_coeff(&cl->lpcm_down_mix_coeff);
1781       return 0;
1782     }
1783   }
1784
1785   if( id1 == 2 ) {
1786     if( id2 == 4 ) {
1787       // Extent start point
1788       return cl->extents.write();
1789     }
1790     if( id2 == 5 ) {
1791       // ProgramInfo SS
1792       return cl->programs_ss.write();
1793     }
1794     if( id2 == 6 ) {
1795       // CPI SS
1796       return cl->cpi_ss.write();
1797     }
1798   }
1799
1800   fprintf(stderr, "write_clpi_extension(): unhandled extension %d.%d\n", id1, id2);
1801   return 1;
1802 }
1803
1804 int
1805 clpi_cl::write()
1806 {
1807   if( write_header() ) return 1;
1808   if( clip.write() ) return 1;
1809   sequence_info_start_addr = bs.posb();
1810   if( sequences.write() ) return 1;
1811   program_info_start_addr = bs.posb();
1812   if( programs.write() ) return 1;
1813   cpi_start_addr = bs.posb();
1814   if( cpi.write() ) return 1;
1815   clip_mark_start_addr = bs.posb();
1816   if( cmrk.write() ) return 1;
1817 //if( has_ext_data ) {
1818 //  ext_data_start_addr = bs.pos();
1819 //  bdmv_write_extension_data(write_clpi_extension, this);
1820 //}
1821   return 0;
1822 }
1823
1824 int
1825 bd_uo_mask::write()
1826 {
1827   bs.write(menu_call, 1);
1828   bs.write(title_search, 1);
1829   bs.write(chapter_search, 1);
1830   bs.write(time_search, 1);
1831   bs.write(skip_to_next_point, 1);
1832   bs.write(skip_to_prev_point, 1);
1833   bs.write(play_firstplay, 1);
1834   bs.write(stop, 1);
1835   bs.write(pause_on, 1);
1836   bs.write(pause_off, 1);
1837   bs.write(still_off, 1);
1838   bs.write(forward, 1);
1839   bs.write(backward, 1);
1840   bs.write(resume, 1);
1841   bs.write(move_up, 1);
1842   bs.write(move_down, 1);
1843   bs.write(move_left, 1);
1844   bs.write(move_right, 1);
1845   bs.write(select, 1);
1846   bs.write(activate, 1);
1847   bs.write(select_and_activate, 1);
1848   bs.write(primary_audio_change, 1);
1849   bs.pad(1);
1850   bs.write(angle_change, 1);
1851   bs.write(popup_on, 1);
1852   bs.write(popup_off, 1);
1853   bs.write(pg_enable_disable, 1);
1854   bs.write(pg_change, 1);
1855   bs.write(secondary_video_enable_disable, 1);
1856   bs.write(secondary_video_change, 1);
1857   bs.write(secondary_audio_enable_disable, 1);
1858   bs.write(secondary_audio_change, 1);
1859   bs.pad(1);
1860   bs.write(pip_pg_change, 1);
1861   bs.pad(30);
1862   return 0;
1863 }
1864
1865 int
1866 mpls_ai::write()
1867 {
1868   bs_len(bs, 32);
1869   bs.pad(8);              // Reserved
1870   bs.write(playback_type, 8);
1871   if (playback_type == BLURAY_PLAYBACK_TYPE_RANDOM ||
1872       playback_type == BLURAY_PLAYBACK_TYPE_SHUFFLE ) {
1873     bs.write(playback_count, 16);
1874   }
1875   else {
1876     bs.pad(16);           // Reserved
1877   }
1878   uo_mask.write();
1879   bs.write(random_access_flag, 1);
1880   bs.write(audio_mix_flag, 1);
1881   bs.write(lossless_bypass_flag, 1);
1882   bs.pad(13);             // Reserved
1883   bs_end(bs);
1884   return 0;
1885 }
1886
1887 int
1888 mpls_pl::write_header()
1889 {
1890   bs.writeb("MPLS", 4);
1891   bs.writeb(sig == 1 ? "0100" : "0200", 4);
1892   bs.write(list_pos, 32);
1893   bs.write(mark_pos, 32);
1894   bs.write(ext_pos, 32);
1895   bs.pad(160);            // Skip 160 reserved bits
1896   app_info.write();
1897   return 0;
1898 }
1899
1900 int mpls_stream::
1901 write()
1902 {
1903   strm.bs_len(bs, 8);
1904
1905   bs.write(stream_type, 8);
1906   switch (stream_type) {
1907   case 0x01:
1908     bs.write(pid, 16);
1909     break;
1910
1911   case 0x02:
1912   case 0x04:
1913     bs.write(subpath_id, 8);
1914     bs.write(subclip_id, 8);
1915     bs.write(pid, 16);
1916     break;
1917
1918   case 0x03:
1919     bs.write(subpath_id, 8);
1920     bs.write(pid, 16);
1921     break;
1922
1923   default:
1924     fprintf(stderr, "unrecognized stream type %02x\n", stream_type);
1925     break;
1926   };
1927   bs.padb(9 - strm.bs_posb(bs));
1928   strm.bs_end(bs);
1929
1930   code.bs_len(bs, 8);
1931   bs.write(coding_type, 8);
1932   switch (coding_type) {
1933   case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1934   case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1935   case BLURAY_STREAM_TYPE_VIDEO_VC1:
1936   case BLURAY_STREAM_TYPE_VIDEO_H264:
1937     bs.write(format, 4);
1938     bs.write(rate, 4);
1939     break;
1940
1941   case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1942   case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1943   case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1944   case BLURAY_STREAM_TYPE_AUDIO_AC3:
1945   case BLURAY_STREAM_TYPE_AUDIO_DTS:
1946   case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1947   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1948   case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1949   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1950   case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1951   case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1952     bs.write(format, 4);
1953     bs.write(rate, 4);
1954     bs.writeb(lang, 3);
1955     break;
1956
1957   case BLURAY_STREAM_TYPE_SUB_PG:
1958   case BLURAY_STREAM_TYPE_SUB_IG:
1959     bs.writeb(lang, 3);
1960     break;
1961
1962   case BLURAY_STREAM_TYPE_SUB_TEXT:
1963     bs.write(char_code, 8);
1964     bs.writeb(lang, 3);
1965     break;
1966
1967   default:
1968     fprintf(stderr, "mpls_stream: unrecognized coding type %02x\n", coding_type);
1969     break;
1970   };
1971   bs.padb(5 - code.bs_posb(bs));
1972   code.bs_end(bs);
1973   return 0;
1974 }
1975
1976 int
1977 mpls_stn::write()
1978 {
1979   bs_len(bs, 16);
1980   bs.pad(16);             // Skip 2 reserved bytes
1981
1982   bs.write(video.size(), 8);
1983   bs.write(audio.size(), 8);
1984   bs.write(pg.size() - num_pip_pg, 8);
1985   bs.write(ig.size(), 8);
1986   bs.write(secondary_audio.size(), 8);
1987   bs.write(secondary_video.size(), 8);
1988   bs.write(num_pip_pg, 8);
1989
1990   // 5 reserve bytes
1991   bs.pad(5 * 8);
1992
1993   // Primary Video Streams
1994   for( int ii=0; ii < video.size(); ++ii )
1995     if( video[ii]->write() ) return 1;
1996
1997   // Primary Audio Streams
1998   for( int ii=0; ii < audio.size(); ++ii )
1999     if( audio[ii]->write() ) return 1;
2000
2001   // Presentation Graphic Streams
2002   for( int ii=0; ii < pg.size(); ++ii )
2003     if( pg[ii]->write() ) return 1;
2004
2005   // Interactive Graphic Streams
2006   for( int ii=0; ii < ig.size(); ++ii )
2007     if( ig[ii]->write() ) return 1;
2008
2009   // Secondary Audio Streams
2010   for( int ii=0; ii < secondary_audio.size(); ++ii ) {
2011     if( secondary_audio[ii]->write() ) return 1;
2012     // Read Secondary Audio Extra Attributes
2013     bs.write(sa_primary_audio_ref.size(), 8);
2014     bs.pad(8);
2015     for( int jj=0; jj < sa_primary_audio_ref.size(); ++jj )
2016       bs.write(sa_primary_audio_ref[jj], 8);
2017     if( sa_primary_audio_ref.size() % 2) bs.pad(8 );
2018   }
2019
2020   // Secondary Video Streams
2021   for( int ii=0; ii < secondary_video.size(); ++ii ) {
2022     if( secondary_video[ii]->write() ) return 1;
2023     // Read Secondary Video Extra Attributes
2024     bs.write(sv_secondary_audio_ref.size(), 8);
2025     bs.pad(8);
2026     for( int jj=0; jj < sv_secondary_audio_ref.size(); ++jj )
2027       bs.write(sv_secondary_audio_ref[jj], 8);
2028     if( sv_secondary_audio_ref.size() % 2) bs.pad(8 );
2029     bs.write(sv_pip_pg_ref.size(), 8);
2030     bs.pad(8);
2031     for( int jj=0; jj < sv_pip_pg_ref.size(); ++jj )
2032       bs.write(sv_pip_pg_ref[jj], 8);
2033     if( sv_pip_pg_ref.size() % 2) bs.pad(8 );
2034   }
2035
2036   bs_end(bs);
2037   return 0;
2038 }
2039
2040 int
2041 mpls_pi::write()
2042 {
2043   bs_len(bs, 16);
2044   // Primary Clip identifer
2045   bs.writeb(clip[0]->clip_id, 5);
2046   bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2047   bs.pad(11); // Skip reserved 11 bits
2048
2049   bs.write(is_multi_angle, 1);
2050   bs.write(connection_condition, 4);  // 0x01, 0x05, 0x06
2051
2052   bs.write(clip[0]->stc_id, 8);
2053   bs.write(in_time, 32);
2054   bs.write(out_time, 32);
2055
2056   uo_mask.write();
2057   bs.write(random_access_flag, 1);
2058   bs.pad(7);
2059   bs.write(still_mode, 8);
2060   if( still_mode == 0x01 ) {
2061     bs.write(still_time, 16);
2062   }
2063   else {
2064     bs.pad(16);
2065   }
2066
2067   if( is_multi_angle ) {
2068     bs.write(clip.size(), 8);
2069     bs.pad(6);
2070     bs.write(is_different_audio, 1);
2071     bs.write(is_seamless_angle, 1);
2072   }
2073
2074   for( int ii=1; ii < clip.size(); ++ii ) {
2075     bs.writeb(clip[ii]->clip_id, 5);
2076     bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2077     bs.write(clip[ii]->stc_id, 8);
2078   }
2079
2080   if( stn.write() ) return 1;
2081
2082   bs_end(bs);
2083   return 0;
2084 }
2085
2086 int
2087 mpls_sub_pi::write()
2088 {
2089   bs_len(bs, 16);
2090   // Primary Clip identifer
2091   bs.writeb(clip[0]->clip_id, 5);
2092   bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2093   bs.pad(27);
2094
2095   bs.write(connection_condition, 4); // 0x01, 0x05, 0x06
2096
2097   bs.write(is_multi_clip, 1);
2098   bs.write(clip[0]->stc_id, 8);
2099   bs.write(in_time, 32);
2100   bs.write(out_time, 32);
2101   bs.write(sync_play_item_id, 16);
2102   bs.write(sync_pts, 32);
2103
2104   if( is_multi_clip )
2105     bs.write(clip.size(), 8);
2106
2107   for( int ii=1; ii < clip.size(); ++ii ) {
2108     // Primary Clip identifer
2109     bs.writeb(clip[ii]->clip_id, 5);
2110     bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2111     bs.write(clip[ii]->stc_id, 8);
2112   }
2113
2114   bs_end(bs);
2115   return 0;
2116 }
2117
2118 int
2119 mpls_sub::write()
2120 {
2121   bs_len(bs, 32);
2122   bs.pad(8);
2123   bs.write(type, 8);
2124   bs.pad(15);
2125   bs.write(is_repeat, 1);
2126   bs.pad(8);
2127   bs.write(sub_play_item.size(), 8);
2128
2129   for( int ii=0; ii < sub_play_item.size(); ++ii )
2130     if( sub_play_item[ii]->write() ) return 1;
2131
2132   bs_end(bs);
2133   return 0;
2134 }
2135
2136 int
2137 mpls_plm::write()
2138 {
2139   bs.write(mark_id, 8);
2140   bs.write(mark_type, 8);
2141   bs.write(play_item_ref, 16);
2142   bs.write(time, 32);
2143   bs.write(entry_es_pid, 16);
2144   bs.write(duration, 32);
2145   return 0;
2146 }
2147
2148 int
2149 mpls_pl::write_playlistmark()
2150 {
2151   mark.bs_len(bs, 32);
2152   // Then get the number of marks
2153   bs.write(play_mark.size(), 16);
2154
2155   for( int ii=0; ii < play_mark.size(); ++ii )
2156     if( play_mark[ii]->write() ) return 1;
2157
2158   mark.bs_end(bs);
2159   return 0;
2160 }
2161
2162 int
2163 mpls_pl::write_playlist()
2164 {
2165   play.bs_len(bs,32);
2166
2167   // Skip reserved bytes
2168   bs.pad(16);
2169
2170   bs.write(play_item.size(), 16);
2171   bs.write(sub_path.size(), 16);
2172
2173   for( int ii=0; ii < play_item.size(); ++ii )
2174     if( play_item[ii]->write() ) return 1;
2175
2176   for( int ii=0; ii < sub_path.size(); ++ii )
2177     if( sub_path[ii]->write() ) return 1;
2178
2179   play.bs_end(bs);
2180   return 0;
2181 }
2182
2183 int
2184 mpls_pip_data::write()
2185 {
2186   bs.write(time, 32);
2187   bs.write(xpos, 12);
2188   bs.write(ypos, 12);
2189   bs.write(scale_factor, 4);
2190   bs.pad(4);
2191   return 0;
2192 }
2193
2194 int
2195 mpls_pip_metadata::write(uint32_t start_address)
2196 {
2197
2198   bs.write(clip_ref, 16);
2199   bs.write(secondary_video_ref, 8);
2200   bs.pad(8);
2201   bs.write(timeline_type, 4);
2202   bs.write(luma_key_flag, 1);
2203   bs.write(trick_play_flag, 1);
2204   bs.pad(10);
2205   if( luma_key_flag ) {
2206     bs.pad(8);
2207     bs.write(upper_limit_luma_key, 8);
2208   }
2209   else {
2210     bs.pad(16);
2211   }
2212   bs.pad(16);
2213
2214   uint32_t data_address = 0;  // XXX
2215   bs.write(data_address, 32);
2216
2217   int64_t pos = bs.pos() / 8;
2218   bs.posb(start_address + data_address);
2219
2220   bs.write(data.size(), 16);
2221   if( data.size() < 1 ) return 1;
2222
2223   for( int ii=0; ii < data.size(); ++ii )
2224     if( data[ii]->write() ) return 1;
2225
2226   bs.posb(pos);
2227   return 0;
2228 }
2229
2230 int
2231 mpls_pl::write_pip_metadata_extension()
2232 {
2233   uint32_t pos = bs.posb();
2234   pipm.bs_len(bs, 32);
2235
2236   bs.write(ext_pip_data.size(), 16);
2237   for( int ii=0; ii < ext_pip_data.size(); ++ii )
2238     if( ext_pip_data[ii]->write(pos) ) return 1;
2239
2240   pipm.bs_end(bs);
2241   return 0;
2242 }
2243
2244 int
2245 mpls_pl::write_subpath_extension()
2246 {
2247   subx.bs_len(bs, 32);
2248
2249   bs.write(ext_sub_path.size(), 16);
2250   for( int ii=0; ii < ext_sub_path.size(); ++ii )
2251     if( ext_sub_path[ii]->write() ) return 1;
2252
2253   subx.bs_end(bs);
2254   return 0;
2255 }
2256
2257 int
2258 clpi_cl::write_mpls_extension(int id1, int id2, void *handle)
2259 {
2260   mpls_pl *pl = (mpls_pl *) handle;
2261
2262   if( id1 == 1 ) {
2263     if( id2 == 1 ) {
2264       // PiP metadata extension
2265       return pl->write_pip_metadata_extension();
2266     }
2267   }
2268
2269   if( id1 == 2 ) {
2270     if( id2 == 1 ) {
2271       return 0;
2272     }
2273     if( id2 == 2 ) {
2274       // SubPath entries extension
2275       return pl->write_subpath_extension();
2276     }
2277   }
2278
2279   return 0;
2280 }
2281
2282 int mpls_pl::
2283 write()
2284 {
2285   int ret = write_header();
2286   list_pos = bs.posb();;
2287   if( !ret ) ret = write_playlist();
2288   mark_pos = bs.posb();
2289   if( !ret ) ret = write_playlistmark();
2290 //if( has_pls_extension ) {
2291 //  ext_pos = bs.posb();
2292 //  bdmv_write_extension_data(write_mpls_extension, pl);
2293   return ret;
2294 }
2295
2296 static int
2297 mk_dir(char *path)
2298 {
2299   if( !mkdir(path, 0777) )
2300     return 0;
2301   perror(path);
2302   return 1;
2303 }
2304
2305 static int
2306 mk_bdmv_dir(char *bdmv_path)
2307 {
2308   if( mk_dir(bdmv_path) )
2309     return 1;
2310   char bdjo_path[BCTEXTLEN];
2311   sprintf(bdjo_path, "%s/BDJO", bdmv_path);
2312   if( mk_dir(bdjo_path) )
2313     return 1;
2314   char clipinf_path[BCTEXTLEN];
2315   sprintf(clipinf_path, "%s/CLIPINF", bdmv_path);
2316   if( mk_dir(clipinf_path) )
2317     return 1;
2318   char jar_path[BCTEXTLEN];
2319   sprintf(jar_path, "%s/JAR", bdmv_path);
2320   if( mk_dir(jar_path) )
2321     return 1;
2322   char playlist_path[BCTEXTLEN];
2323   sprintf(playlist_path, "%s/PLAYLIST", bdmv_path);
2324   if( mk_dir(playlist_path) )
2325     return 1;
2326   return 0;
2327 }
2328
2329 static int
2330 mkbdmv(char *path)
2331 {
2332   char bdmv_path[BCTEXTLEN];
2333   sprintf(bdmv_path, "%s/BDMV", path);
2334   if( mk_bdmv_dir(bdmv_path) ) return 1;
2335   char cert_path[BCTEXTLEN];
2336   sprintf(cert_path, "%s/CERTIFICATE", path);
2337   if( mk_bdmv_dir(cert_path) ) return 1;
2338   char cert_backup[BCTEXTLEN];
2339   sprintf(cert_backup, "%s/BACKUP", cert_path);
2340   if( mk_bdmv_dir(cert_backup) ) return 1;
2341   char stream_path[BCTEXTLEN];
2342   sprintf(stream_path, "%s/STREAM", bdmv_path);
2343   if( mk_dir(stream_path) ) return 1;
2344   char auxdata_path[BCTEXTLEN];
2345   sprintf(auxdata_path, "%s/AUXDATA", bdmv_path);
2346   if( mk_dir(auxdata_path) ) return 1;
2347   char meta_path[BCTEXTLEN];
2348   sprintf(meta_path, "%s/META", bdmv_path);
2349   if( mk_dir(meta_path) ) return 1;
2350   char backup_path[BCTEXTLEN];
2351   sprintf(backup_path, "%s/BACKUP", bdmv_path);
2352   if( mk_bdmv_dir(backup_path) ) return 1;
2353   return 0;
2354 }
2355
2356 int program::
2357 build_toc(clpi_ep_map_entry *map)
2358 {
2359   clpi_ep_coarse *cp = 0;
2360   marks.sort(mark::cmpr);
2361   uint16_t ep_pid = map->pid;
2362   int64_t last_pts = -1, last_pkt = -1;
2363   for( int ii=0; ii<marks.size(); ++ii ) {
2364     mark *mp = marks[ii];
2365     if( mp->pid != ep_pid ) continue;
2366     int64_t pts = mp->pts;
2367     if( last_pts >= pts ) continue;
2368     last_pts = pts;
2369     uint32_t pkt = mp->pos / BLURAY_TS_PKTSZ;
2370     if( last_pkt >= pkt ) continue;
2371     last_pkt = pkt;
2372     int64_t coarse_pts = (pts >> 18); // & ~0x01;
2373     int64_t fine_pts = (pts & 0x7ffff) >> 8;
2374     uint32_t mpkt = pkt & ~0x1ffff;
2375     if( !cp || cp->pts_ep != coarse_pts || mpkt > cp->spn_ep ) {
2376       cp = new clpi_ep_coarse();
2377       map->coarse.append(cp);
2378       cp->ref_ep_fine_id = map->fine.size();
2379       cp->pts_ep = coarse_pts;
2380       cp->spn_ep = pkt;
2381     }
2382     clpi_ep_fine *fp = new clpi_ep_fine();
2383     map->fine.append(fp);
2384     fp->is_angle_change_point = 0;
2385 // XXX - dont know what this is
2386     fp->i_end_position_offset = 1;
2387     fp->pts_ep = fine_pts;
2388     fp->spn_ep = pkt & 0x1ffff;
2389   }
2390   return 0;
2391 }
2392
2393 const AVRational media_info::clk45k = { 1, 45000 };
2394
2395 static int bd_stream_type(AVCodecID codec_id)
2396 {
2397   int stream_type = 0;
2398   switch (codec_id) {
2399   case AV_CODEC_ID_MPEG1VIDEO:
2400     stream_type = BLURAY_STREAM_TYPE_VIDEO_MPEG1;
2401     break;
2402   case AV_CODEC_ID_MPEG2VIDEO:
2403     stream_type = BLURAY_STREAM_TYPE_VIDEO_MPEG2;
2404     break;
2405   case AV_CODEC_ID_H264:
2406     stream_type = BLURAY_STREAM_TYPE_VIDEO_H264;
2407     break;
2408   case AV_CODEC_ID_MP2:
2409     stream_type = BLURAY_STREAM_TYPE_AUDIO_MPEG1;
2410     break;
2411   case AV_CODEC_ID_MP3:
2412     stream_type = BLURAY_STREAM_TYPE_AUDIO_MPEG2;
2413     break;
2414   case AV_CODEC_ID_AC3:
2415     stream_type = BLURAY_STREAM_TYPE_AUDIO_AC3;
2416     break;
2417   case AV_CODEC_ID_EAC3:
2418     stream_type = BLURAY_STREAM_TYPE_AUDIO_AC3PLUS;
2419     break;
2420   case AV_CODEC_ID_DTS:
2421     stream_type = BLURAY_STREAM_TYPE_AUDIO_DTS;
2422     break;
2423   case AV_CODEC_ID_TRUEHD:
2424     stream_type = BLURAY_STREAM_TYPE_AUDIO_TRUHD;
2425     break;
2426   case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
2427     stream_type = BLURAY_STREAM_TYPE_SUB_PG;
2428     break;
2429   default:
2430     fprintf(stderr, "unknown bluray stream type %s\n", avcodec_get_name(codec_id));
2431     exit(1);
2432   }
2433   return stream_type;
2434 }
2435
2436 static int bd_audio_format(int channels)
2437 {
2438   int audio_format = 0;
2439   switch( channels ) {
2440   case 1:
2441     audio_format = BLURAY_AUDIO_FORMAT_MONO;
2442     break;
2443   case 2:
2444     audio_format = BLURAY_AUDIO_FORMAT_STEREO;
2445     break;
2446   case 6:
2447     audio_format = BLURAY_AUDIO_FORMAT_MULTI_CHAN;
2448     break;
2449   default:
2450     fprintf(stderr, "unknown bluray audio format %d ch\n", channels);
2451     exit(1);
2452   }
2453   return audio_format;
2454 }
2455
2456 static int bd_audio_rate(int rate)
2457 {
2458   int audio_rate = 0;
2459   switch( rate ) {
2460   case 48000:  audio_rate = BLURAY_AUDIO_RATE_48;  break;
2461   case 96000:  audio_rate = BLURAY_AUDIO_RATE_96;  break;
2462   case 192000: audio_rate = BLURAY_AUDIO_RATE_192; break;
2463   default:
2464     fprintf(stderr, "unknown bluray audio rate %d\n", rate);
2465     exit(1);
2466   }
2467   return audio_rate;
2468 }
2469
2470 static int bd_video_format(int w, int h, int ilace)
2471 {
2472   if( w ==  720 && h ==  480    &&  ilace   ) return BLURAY_VIDEO_FORMAT_480I;
2473   if( w ==  720 && h ==  576    &&  ilace   ) return BLURAY_VIDEO_FORMAT_576I;
2474   if( w ==  720 && h ==  480    && !ilace   ) return BLURAY_VIDEO_FORMAT_480P;
2475   if( w ==  720 && h ==  576    && !ilace   ) return BLURAY_VIDEO_FORMAT_576P;
2476 // this seems to be overly restrictive
2477   if( w == 1280 && h ==  720 /* && !ilace*/ ) return BLURAY_VIDEO_FORMAT_720P;
2478   if( w == 1440 && h == 1080 /* &&  ilace*/ ) return BLURAY_VIDEO_FORMAT_1080I;
2479   if( w == 1920 && h == 1080 /* && !ilace*/ ) return BLURAY_VIDEO_FORMAT_1080P;
2480   fprintf(stderr, "unknown bluray video format %dx%d %silace\n",
2481     w, h, !ilace ? "not " : "");
2482   exit(1);
2483 }
2484
2485 static int bd_video_rate(double rate)
2486 {
2487   if( fabs(rate-23.976) < 0.01 ) return BLURAY_VIDEO_RATE_24000_1001;
2488   if( fabs(rate-24.000) < 0.01 ) return BLURAY_VIDEO_RATE_24;
2489   if( fabs(rate-25.000) < 0.01 ) return BLURAY_VIDEO_RATE_25;
2490   if( fabs(rate-29.970) < 0.01 ) return BLURAY_VIDEO_RATE_30000_1001;
2491   if( fabs(rate-50.000) < 0.01 ) return BLURAY_VIDEO_RATE_50;
2492   if( fabs(rate-59.940) < 0.01 ) return BLURAY_VIDEO_RATE_60000_1001;
2493   fprintf(stderr, "unknown bluray video framerate %5.2f\n",rate);
2494   exit(1);
2495 }
2496
2497 static int bd_aspect_ratio(int w, int h, double ratio)
2498 {
2499   double aspect = (w * ratio) / h;
2500   if( fabs(aspect-1.333) < 0.01 ) return BLURAY_ASPECT_RATIO_4_3;
2501   if( fabs(aspect-1.777) < 0.01 ) return BLURAY_ASPECT_RATIO_16_9;
2502   return w == 720 ? BLURAY_ASPECT_RATIO_4_3 : BLURAY_ASPECT_RATIO_16_9;
2503   fprintf(stderr, "unknown bluray aspect ratio %5.3f\n",aspect);
2504   exit(1);
2505 }
2506
2507 static int field_probe(AVFormatContext *fmt_ctx, AVStream *st)
2508 {
2509   AVDictionary *copts = 0;
2510   //av_dict_copy(&copts, opts, 0);
2511   AVCodecID codec_id = st->codec->codec_id;
2512   AVCodec *decoder = avcodec_find_decoder(codec_id);
2513   if( avcodec_open2(st->codec, decoder, &copts) < 0 ) {
2514     fprintf(stderr,"codec open failed\n");
2515     return -1;
2516   }
2517   av_dict_free(&copts);
2518
2519   AVFrame *ipic = av_frame_alloc();
2520   AVPacket ipkt;
2521   av_init_packet(&ipkt);
2522   int ilaced = -1;
2523   for( int retrys=100; --retrys>=0 && ilaced<0; ) {
2524     av_packet_unref(&ipkt);
2525     int ret = av_read_frame(fmt_ctx, &ipkt);
2526     if( ret == AVERROR_EOF ) break;
2527     if( ret != 0 ) continue;
2528     if( !ipkt.data ) continue;
2529     if( ipkt.stream_index != st->index ) continue;
2530     while( ipkt.size > 0 ) {
2531       int got_frame = 0;
2532       ret = avcodec_decode_video2(st->codec, ipic, &got_frame, &ipkt);
2533       if( ret <= 0 ) break;
2534       if( got_frame ) {
2535         ilaced = ipic->interlaced_frame ? 1 : 0;
2536         break;
2537       }
2538       ipkt.data += ret;
2539       ipkt.size -= ret;
2540     }
2541   }
2542   av_packet_unref(&ipkt);
2543   av_frame_free(&ipic);
2544   return ilaced;
2545 }
2546
2547 int media_info::scan()
2548 {
2549   struct stat st;
2550   if( stat(filename, &st) ) return 1;
2551   file_size = st.st_size;
2552
2553   AVFormatContext *fmt_ctx = 0;
2554   AVDictionary *fopts = 0;
2555   av_dict_set(&fopts, "formatprobesize", "5000000", 0);
2556   av_dict_set(&fopts, "scan_all_pmts", "1", 0);
2557   av_dict_set(&fopts, "threads", "auto", 0);
2558   int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
2559   av_dict_free(&fopts);
2560   if( ret < 0 ) return ret;
2561   ret = avformat_find_stream_info(fmt_ctx, NULL);
2562
2563   bit_rate = fmt_ctx->bit_rate;
2564
2565   int ep_pid = -1;
2566   for( int i=0; ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
2567     AVStream *st = fmt_ctx->streams[i];
2568     AVMediaType type = st->codec->codec_type;
2569     switch( type ) {
2570     case AVMEDIA_TYPE_VIDEO: break;
2571     case AVMEDIA_TYPE_AUDIO: break;
2572     case AVMEDIA_TYPE_SUBTITLE: break;
2573     default: continue;
2574     }
2575     stream *s = new stream(type, i);
2576     s->pid = st->id;
2577     AVCodecID codec_id = st->codec->codec_id;
2578     switch( type ) {
2579     case AVMEDIA_TYPE_VIDEO: {
2580       if( ep_pid < 0 ) ep_pid = st->id;
2581       s->coding_type = bd_stream_type(codec_id);
2582       int ilace = field_probe(fmt_ctx, st);
2583       if( ilace < 0 ) {
2584         fprintf(stderr, "interlace probe failed\n");
2585         exit(1);
2586       }
2587       s->format = bd_video_format(st->codec->width, st->codec->height, ilace);
2588       s->rate = bd_video_rate(!st->codec->framerate.den ? 0 :
2589                 (double)st->codec->framerate.num / st->codec->framerate.den);
2590       s->aspect = bd_aspect_ratio(st->codec->width, st->codec->height,
2591                 !st->sample_aspect_ratio.num || !st->sample_aspect_ratio.den ? 1. :
2592                  (double)st->sample_aspect_ratio.num / st->sample_aspect_ratio.den);
2593       break; }
2594     case AVMEDIA_TYPE_AUDIO: {
2595       s->coding_type = bd_stream_type(codec_id);
2596       s->format = bd_audio_format(st->codec->channels);
2597       s->rate = bd_audio_rate(st->codec->sample_rate);
2598       strcpy((char*)s->lang, "eng");
2599       break; }
2600     case AVMEDIA_TYPE_SUBTITLE: {
2601       s->coding_type = bd_stream_type(codec_id);
2602       AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", 0, 0);
2603       strncpy((char*)s->lang, lang ? lang->value : "und", sizeof(s->lang));
2604       break; }
2605     default:
2606       break;
2607     }
2608     if( bit_rate > 0 && st->duration == AV_NOPTS_VALUE &&
2609         st->time_base.num < INT64_MAX / bit_rate ) {
2610       st->duration = av_rescale(8*file_size, st->time_base.den,
2611           bit_rate * (int64_t) st->time_base.num);
2612     }
2613     s->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2614     streams.append(s);
2615
2616     AVCodec *decoder = avcodec_find_decoder(codec_id);
2617     AVDictionary *copts = 0;
2618     ret = avcodec_open2(st->codec, decoder, &copts);
2619   }
2620   if( ep_pid < 0 )
2621     ep_pid = fmt_ctx->nb_streams > 0 ? fmt_ctx->streams[0]->id : 0;
2622
2623   int npgm = fmt_ctx->nb_programs;
2624   if( npgm < 1 ) {
2625     program *pgm = new program(-1, 1);
2626     pgm->ep_pid = ep_pid;
2627     pgm->pmt_pid = 0x1000;
2628     pgm->pcr_pid = 0x1001;
2629     pgm->duration = 0;
2630     for( int jj=0; jj<streams.size(); ++jj ) {
2631       AVStream *st = fmt_ctx->streams[jj];
2632       AVMediaType type = st->codec->codec_type;
2633       switch( type ) {
2634       case AVMEDIA_TYPE_VIDEO:
2635       case AVMEDIA_TYPE_AUDIO:
2636         break;
2637       default:
2638         continue;
2639       }
2640       pgm->strm_idx.append(jj);
2641       if( pgm->duration < st->duration )
2642         pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2643     }
2644     programs.append(pgm);
2645   }
2646
2647   for( int ii=0; ii<npgm; ++ii ) {
2648     AVProgram *pgrm = fmt_ctx->programs[ii];
2649     program *pgm = new program(ii, pgrm->id);
2650     pgm->pmt_pid = pgrm->pmt_pid;
2651     pgm->pcr_pid = pgrm->pcr_pid;
2652     pgm->duration = 0;
2653     ep_pid = -1;
2654     for( int jj=0; jj<(int)pgrm->nb_stream_indexes; ++jj ) {
2655       int av_idx = pgrm->stream_index[jj];
2656       AVStream *st = fmt_ctx->streams[av_idx];
2657       AVMediaType type = st->codec->codec_type;
2658       switch( type ) {
2659       case AVMEDIA_TYPE_VIDEO:
2660         if( ep_pid < 0 ) ep_pid = st->id;
2661         break;
2662       case AVMEDIA_TYPE_AUDIO:
2663       case AVMEDIA_TYPE_SUBTITLE:
2664         break;
2665       default:
2666         continue;
2667       }
2668       int sidx = streams.size();
2669       while( --sidx>=0 && streams[sidx]->av_idx!=av_idx );
2670       if( sidx < 0 ) {
2671         fprintf(stderr, "bad stream idx %d in pgm %d\n",av_idx, ii);
2672         continue;
2673       }
2674       if( pgm->duration < st->duration )
2675         pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2676       pgm->strm_idx.append(sidx);
2677     }
2678     if( ep_pid < 0 ) {
2679       AVProgram *pgrm = fmt_ctx->programs[0];
2680       ep_pid = pgrm->nb_stream_indexes > 0 ?
2681           fmt_ctx->streams[pgrm->stream_index[0]]->id : 0;
2682     }
2683     pgm->ep_pid = ep_pid;
2684     programs.append(pgm);
2685   }
2686
2687   if( ret >= 0 )
2688     ret = scan(fmt_ctx);
2689
2690   for( int i=0; i<(int)fmt_ctx->nb_streams; ++i )
2691     avcodec_close(fmt_ctx->streams[i]->codec);
2692   avformat_close_input(&fmt_ctx);
2693
2694   return ret;
2695 }
2696
2697 int media_info::scan(AVFormatContext *fmt_ctx)
2698 {
2699   int ret = 0;
2700   AVPacket ipkt;
2701   av_init_packet(&ipkt);
2702 #if 1
2703 // zero pts at pos zero
2704   for( int i=0; i<programs.size(); ++i ) {
2705     program *p = programs[i];
2706     for( int j=0; j<p->strm_idx.size(); ++j ) {
2707       stream *sp = streams[p->strm_idx[j]];
2708       sp->last_pts = 0;
2709       AVStream *st = fmt_ctx->streams[sp->av_idx];
2710       p->add_label(0, 0, 0, st->id);
2711     }
2712   }
2713 #endif
2714   for( int64_t count=0; ret>=0; ++count ) {
2715     av_packet_unref(&ipkt);
2716     ipkt.data = 0; ipkt.size = 0;
2717
2718     ret = av_read_frame(fmt_ctx, &ipkt);
2719     if( ret < 0 ) {
2720       if( ret == AVERROR_EOF ) break;
2721       ret = 0;
2722       continue;
2723     }
2724     if( !ipkt.data ) continue;
2725     if( (ipkt.flags & AV_PKT_FLAG_CORRUPT) ) continue;
2726     if( ipkt.pts == AV_NOPTS_VALUE ) continue;
2727     int i = ipkt.stream_index;
2728     if( i < 0 || i >= streams.size() ) continue;
2729
2730     stream *sp = 0;
2731     program *pgm = 0;
2732     for( int ii=0; !pgm && ii<programs.size(); ++ii ) {
2733       program *p = programs[ii];
2734       for( int jj=0; jj<p->strm_idx.size(); ++jj ) {
2735         sp = streams[p->strm_idx[jj]];
2736         if( sp->av_idx == i ) { pgm = p;  break; }
2737       }
2738     }
2739     if( !pgm ) continue;
2740     AVStream *st = fmt_ctx->streams[i];
2741     if( pgm->ep_pid != st->id ) continue;
2742     int64_t pts45k = av_rescale_q(ipkt.pts, st->time_base, clk45k);
2743     if( sp->start_pts > pts45k ) sp->start_pts = pts45k;
2744     if( sp->end_pts < pts45k ) sp->end_pts = pts45k;
2745     if( pgm->start_time > pts45k ) pgm->start_time = pts45k;
2746     if( pgm->end_time < pts45k ) pgm->end_time = pts45k;
2747
2748     if( !(ipkt.flags & AV_PKT_FLAG_KEY) ) continue;
2749
2750     if( sp->last_pts != pts45k ) {
2751       sp->last_pts = pts45k;
2752       pgm->add_label(count, ipkt.pos, pts45k, st->id);
2753     }
2754   }
2755
2756   for( int ii=0; ii<programs.size(); ++ii ) {
2757     program *pgm = programs[ii];
2758     if( pgm->end_time > pgm->start_time )
2759       pgm->duration = pgm->end_time - pgm->start_time;
2760   }
2761
2762   return ret != AVERROR_EOF ? -1 : 0;
2763 }
2764
2765 void
2766 Media::add_movie(uint32_t *ops, int n)
2767 {
2768   movie_obj *mp = new movie_obj();
2769   mp->resume_intention_flag = 1;
2770   uint32_t *eop = ops + n/sizeof(*ops);
2771   while( ops < eop ) {
2772     command_obj *cmd = new command_obj();
2773     cmd->cmd = htobe32(*ops++);
2774     cmd->dst = *ops++;
2775     cmd->src = *ops++;
2776     mp->cmds.append(cmd);
2777   }
2778   mov.movies.append(mp);
2779 }
2780
2781 int
2782 Media::compose()
2783 {
2784 // movie
2785   bs.init();
2786
2787 // top menu
2788   int top_menu_obj = mov.movies.size();
2789   movie_obj *mp = new movie_obj();
2790   mp->resume_intention_flag = 1;
2791   command_obj *cmd = new command_obj();
2792   cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
2793   mp->cmds.append(cmd);  // JUMP_TITLE 1
2794   mov.movies.append(mp);
2795
2796 // titles
2797   for( int ii=0; ii<size(); ++ii ) {
2798     mp = new movie_obj();
2799     mp->resume_intention_flag = 1;
2800     cmd = new command_obj();
2801     cmd->cmd = htobe32(0x22800000); cmd->dst = ii; cmd->src = 0;
2802     mp->cmds.append(cmd);  // PLAY_PL   ii
2803     cmd = new command_obj();
2804     cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2805     mp->cmds.append(cmd);
2806     mov.movies.append(mp); // BREAK
2807   }
2808
2809 // first play
2810   int first_play_obj = mov.movies.size();
2811   mp = new movie_obj();
2812   mp->resume_intention_flag = 1;
2813   cmd = new command_obj();
2814   cmd->cmd = htobe32(0x21810000); cmd->dst = 0; cmd->src = 0;
2815   mp->cmds.append(cmd);  // JUMP_TITLE 0 ; top menu
2816   mov.movies.append(mp);
2817
2818 // index
2819   bs.init();
2820   idx.first_play.set_hdmv(first_play_obj, pb_typ_iactv);
2821   idx.top_menu.set_hdmv(top_menu_obj, pb_typ_iactv);
2822
2823   title_obj *tp = 0;
2824 // clips
2825   for( int ii=0; ii<size(); ++ii ) {
2826     if( !tp ) {
2827       tp = new title_obj();
2828       tp->set_hdmv(idx.titles.size()+1, pb_typ_movie);
2829       idx.titles.append(tp);
2830     }
2831     bs.init();
2832     media_info *ip = get(ii);
2833 // clip program, if specified
2834     int pidx = ip->programs.size();
2835     while( --pidx>=0 && ip->programs[pidx]->pid != ip->pgm_pid );
2836     if( pidx < 0 ) pidx = 0;
2837     ip->pidx = pidx;
2838     ip->pgm_pid = ip->prog()->pid;
2839
2840     clpi_cl *cp = new clpi_cl();
2841     cp->clip.clip_stream_type = 1;
2842     cp->clip.application_type = BLURAY_APP_TYPE_MAIN_MOVIE;
2843     cp->clip.ts_recording_rate = ip->bit_rate;
2844     uint32_t ts_pkt_count = ip->file_size / BLURAY_TS_PKTSZ;
2845     cp->clip.num_source_packets = ts_pkt_count;
2846     cp->clip.ts_type_info.validity = 0x80;
2847     strcpy(cp->clip.ts_type_info.format_id, "HDMV");
2848     cp->cpi.type = 1;
2849
2850     for( int jj=0; jj<ip->programs.size(); ++jj ) {
2851       program *pgm = ip->programs[jj];
2852       clpi_prog *p = new clpi_prog(pgm->pmt_pid);
2853       for( int kk=0; kk<pgm->strm_idx.size(); ++kk ) {
2854         int k = pgm->strm_idx[kk];
2855         stream *sp = ip->streams[k];
2856         clpi_prog_stream *s = new clpi_prog_stream();
2857         s->pid = sp->pid;
2858         s->coding_type = sp->coding_type;
2859         s->format = sp->format;
2860 //use unspecified (0)
2861 //      if( !idx.video_format ) idx.video_format = s->format;
2862         s->rate = sp->rate;
2863 //      if( !idx.frame_rate ) idx.frame_rate = s->rate;
2864         switch( sp->type ) {
2865         case AVMEDIA_TYPE_VIDEO:
2866           s->aspect = sp->aspect;
2867           break;
2868         case AVMEDIA_TYPE_AUDIO:
2869         case AVMEDIA_TYPE_SUBTITLE:
2870           memcpy(s->lang,sp->lang,sizeof(s->lang));
2871           break;
2872         default:
2873           break;
2874         }
2875         p->streams.append(s);
2876       }
2877       clpi_ep_map_entry *map = new clpi_ep_map_entry(pgm->ep_pid);
2878       map->ep_stream_type = 1;
2879       pgm->build_toc(map);
2880       cp->cpi.append(map);
2881       cp->programs.append(p);
2882
2883       clpi_atc_seq *atc_seq = new clpi_atc_seq();
2884       clpi_stc_seq *stc_seq = new clpi_stc_seq();
2885       stc_seq->pcr_pid = pgm->pcr_pid;
2886       stc_seq->presentation_start_time = pgm->start_time;
2887       stc_seq->presentation_end_time = pgm->end_time;
2888       atc_seq->stc_seq.append(stc_seq);
2889       cp->sequences.append(atc_seq);
2890     }
2891
2892     cl.append(cp);
2893     tp->last = ii;
2894     if( ip->brk ) tp = 0;
2895   }
2896
2897 // playlists, one per title
2898 //   one playitem per media clip
2899   int clip_id = 0;
2900   for( int ii=0; ii<idx.titles.size(); ++ii ) {
2901     bs.init();
2902     media_info *ip = get(clip_id);
2903     program *pgm = ip->prog();
2904     mpls_pl *pp = new mpls_pl();
2905     pp->app_info.playback_type = BLURAY_PLAYBACK_TYPE_SEQUENTIAL;
2906 //  pp->app_info.uo_mask.xxx = 1;
2907     int last = idx.titles[ii]->last;
2908     for( ; clip_id<=last; ++clip_id ) {
2909       ip = get(clip_id);
2910       pgm = ip->prog();
2911       mpls_pi *pi = new mpls_pi();
2912       pi->connection_condition = 1; // seamless
2913 //    pi->uo_mask.xxx = 1;
2914       pi->in_time = pgm->start_time;
2915       pi->out_time = pgm->end_time;
2916       if( ip->still )
2917         pi->still_mode = BLURAY_STILL_INFINITE;
2918       int64_t end_time = pgm->start_time + pgm->duration;
2919       if( pi->out_time < end_time ) pi->out_time = end_time;
2920       mpls_clip *cp = new mpls_clip();
2921       sprintf(cp->clip_id,"%05d", clip_id);
2922       pi->clip.append(cp);
2923       for( int kk=0; kk<ip->streams.size(); ++kk ) {
2924         stream *sp = ip->streams[kk];
2925         switch( sp->type ) {
2926         case AVMEDIA_TYPE_VIDEO: break;
2927         case AVMEDIA_TYPE_AUDIO: break;
2928         case AVMEDIA_TYPE_SUBTITLE: break;
2929         default: continue;
2930         }
2931         mpls_stream *ps = new mpls_stream();
2932         ps->pid = sp->pid;
2933         ps->stream_type = BLURAY_PG_TEXTST_STREAM;
2934         ps->coding_type = sp->coding_type;
2935         ps->format = sp->format;
2936         ps->rate = sp->rate;
2937         switch( sp->type ) {
2938         case AVMEDIA_TYPE_VIDEO:
2939           pi->stn.video.append(ps);
2940           break;
2941         case AVMEDIA_TYPE_AUDIO:
2942           memcpy(ps->lang, sp->lang, sizeof(ps->lang));
2943           pi->stn.audio.append(ps);
2944           break;
2945         case AVMEDIA_TYPE_SUBTITLE:
2946           memcpy(ps->lang, sp->lang, sizeof(ps->lang));
2947           pi->stn.pg.append(ps);
2948           break;
2949         default:
2950           break;
2951         }
2952       }
2953       pp->play_item.append(pi);
2954     }
2955 // chapter marks every ch_duration ticks
2956     int64_t ch_duration = 45000 * 60*5;
2957     int64_t mrktm = ch_duration;
2958     int64_t plytm = 0;
2959     int pmark = 0, pitem = 0;
2960     mpls_pi *pi = pp->play_item[pitem];
2961     mpls_plm *pm = new mpls_plm();
2962     pm->mark_id = pmark++;
2963     pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2964     pm->play_item_ref = pitem;
2965     pm->time = pi->in_time;
2966     pm->entry_es_pid = 0;
2967     pp->play_mark.append(pm);
2968     for( int jj=0; jj < pp->play_item.size(); ++jj ) {
2969       pitem = jj;
2970       pi = pp->play_item[pitem];
2971       int64_t pi_duration = pi->out_time - pi->in_time;
2972       int64_t endtm = plytm + pi_duration;
2973       while( mrktm < endtm ) {
2974         pm = new mpls_plm();
2975         pm->mark_id = pmark++;
2976         pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2977         pm->play_item_ref = pitem;
2978         pm->time = pi->in_time + mrktm - plytm;
2979         pm->entry_es_pid = 0;
2980         pp->play_mark.append(pm);
2981         mrktm += ch_duration;
2982       }
2983       plytm = endtm;
2984     }
2985     pm = new mpls_plm();
2986     pm->mark_id = pmark;
2987     pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2988     pm->play_item_ref = pitem;
2989     pm->time = pi->out_time;
2990     pm->entry_es_pid = 0;
2991     pp->play_mark.append(pm);
2992
2993     pl.append(pp);
2994   }
2995   return 0;
2996 }
2997
2998 int Media::
2999 bd_path(const char *bp, const char *fmt, va_list ap)
3000 {
3001   int n = sizeof(filename)-1;
3002   char *cp = filename;
3003   const char *pp = path;
3004   while( n>0 && (*cp=*pp)!=0 ) { --n;  ++cp;  ++pp; }
3005   while( n>0 && (*cp=*bp)!=0 ) { --n;  ++cp;  ++bp; }
3006   n -= vsnprintf(cp, n, fmt, ap);
3007   va_end(ap);
3008   return n > 0 ? 0 : 1;
3009 }
3010
3011 int Media::
3012 bd_copy(const char *ifn, const char *fmt, ...)
3013 {
3014   int bfrsz = 0x40000, ret = 1;
3015   char bfr[bfrsz];
3016   FILE *ifp = fopen(ifn,"r");
3017   if( ifp ) {
3018     va_list ap;
3019     va_start(ap, fmt);
3020     if( bd_path("/BDMV/", fmt, ap) ) return 1;
3021     va_end(ap);
3022     FILE *ofp = fopen(filename,"w");
3023     if( ofp ) {
3024       setvbuf(ifp, 0, _IOFBF, 0x80000);
3025       setvbuf(ofp, 0, _IOFBF, 0x80000);
3026       ret = 0;
3027       int n = bfrsz;
3028       while( !ret && n >= bfrsz ) {
3029         n = fread(bfr,1,bfrsz,ifp);
3030         if( n > 0 && (int)fwrite(bfr,1,n,ofp) != n ) {
3031           fprintf(stderr, "cant write: %s\n",filename);
3032           ret = 1;
3033         }
3034       }
3035       if( ferror(ifp) ) {
3036         fprintf(stderr, "read error: %s = %m\n",ifn);
3037         ret = 1;
3038       }
3039       if( ferror(ofp) ) {
3040         fprintf(stderr, "write error: %s = %m\n",filename);
3041         ret = 1;
3042       }
3043       if( fclose(ofp) ) {
3044         fprintf(stderr, "close error: %s = %m\n",filename);
3045         ret = 1;
3046       }
3047     }
3048     fclose(ifp);
3049   }
3050   if( ret )
3051     fprintf(stderr, "cant copy clip %s\n",ifn);
3052   return ret;
3053 }
3054
3055 int Media::
3056 bd_open(const char *fmt, ...)
3057 {
3058   bs.init();
3059   if( !path ) return 0;
3060   va_list ap;
3061   va_start(ap, fmt);
3062   if( bd_path("/BDMV/", fmt, ap) ) return 1;
3063   va_end(ap);
3064   if( bs.open(filename) ) {
3065     fprintf(stderr, "cant open file %s\n",filename);
3066     return 1;
3067   }
3068   return 0;
3069 }
3070
3071 int Media::
3072 bd_backup(const char *fmt, ...)
3073 {
3074   bs.close();
3075   if( !path ) return 0;
3076   int n, ret = 1;
3077   char bfr[0x10000];
3078   FILE *ifp = fopen(filename,"r");
3079   if( ifp ) {
3080     va_list ap;
3081     va_start(ap, fmt);
3082     if( bd_path("/BDMV/BACKUP/", fmt, ap) ) return 1;
3083     va_end(ap);
3084     FILE *ofp = fopen(filename,"w");
3085     if( ofp ) {
3086       while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
3087       fclose(ofp);
3088       ret = 0;
3089     }
3090     fclose(ifp);
3091   }
3092   if( ret )
3093     fprintf(stderr, "cant backup %s\n",filename);
3094   return ret;
3095 }
3096
3097 int Media::write(char *fn)
3098 {
3099   this->path = fn;
3100 // index
3101   if( bd_open("index.bdmv") ) return 1;
3102   if( idx.write() ) return 1;
3103   if( bd_backup("index.bdmv") ) return 1;
3104 // movie
3105   if( bd_open("MovieObject.bdmv") ) return 1;
3106   if( mov.write() ) return 1;
3107   if( bd_backup("MovieObject.bdmv") ) return 1;
3108 // clips
3109   for( int ii=0; ii<cl.size(); ++ii ) {
3110     if( bd_open("CLIPINF/%05d.clpi", ii) ) return 1;
3111     if( cl[ii]->write() ) return 1;
3112     if( bd_backup("CLIPINF/%05d.clpi", ii) ) return 1;
3113   }
3114 // playlists
3115   for( int ii=0; ii<pl.size(); ++ii ) {
3116     if( bd_open("PLAYLIST/%05d.mpls", ii) ) return 1;
3117     if( pl[ii]->write() ) return 1;
3118     if( bd_backup("PLAYLIST/%05d.mpls", ii) ) return 1;
3119   }
3120   return 0;
3121 }
3122
3123 int
3124 main(int ac, char **av)
3125 {
3126   char *path = av[1];
3127   if( mkbdmv(path) ) return 1;
3128   av_register_all();
3129   av_log_set_level(AV_LOG_FATAL);
3130   //av_log_set_level(AV_LOG_VERBOSE);
3131   //av_log_set_level(AV_LOG_DEBUG);
3132   Media media;
3133   media_info *mp = 0;
3134
3135   for( int ii=2; ii<ac; ++ii ) {
3136     char *ap = av[ii];
3137     // any dash seq followed by number sets curr title pgm_pid
3138     // single dash only sets title pgm_pid
3139     // double dash ends curr title, starts a new title
3140     // triple dash ends curr title as infinite still
3141     if( *ap == '-' ) {
3142       if( !mp ) continue;
3143       if( *++ap == '-' ) {
3144         mp->brk = 1;
3145         if( *++ap == '-' ) { ++ap;  mp->still = 1; }
3146       }
3147       if( *ap >= '0' && *ap <= '9' )
3148         mp->pgm_pid = strtoul(ap,&ap,0);
3149       if( mp->brk ) mp = 0;
3150       if( !ap || *ap ) {
3151         fprintf(stderr, "err arg %d: %s\n",ii,av[ii]);
3152         return 1;
3153       }
3154       continue;
3155     }
3156     mp = new media_info(av[ii]);
3157     media.append(mp);
3158     if( mp->scan() ) {
3159       fprintf(stderr, "cant scan media: %s\n", av[ii]);
3160       return 1;
3161     }
3162   }
3163
3164   if( mp ) mp->brk = 1;
3165
3166   if( media.compose() ) {
3167     fprintf(stderr, "cant compose media\n");
3168     return 1;
3169   }
3170   if( media.write(0) ) {
3171     fprintf(stderr, "cant prepare media\n");
3172     return 1;
3173   }
3174   if( media.write(path) ) {
3175     fprintf(stderr, "cant write media\n");
3176     return 1;
3177   }
3178
3179   for( int ii=0; ii<media.size(); ++ii )
3180     if( media.bd_copy(media[ii]->filename, "STREAM/%05d.m2ts", ii) )
3181       return 1;
3182
3183   return 0;
3184 }
3185