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