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.
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>
13 // ./brwrite /tmp/dir /path/menu.m2ts --- /path/clip0.m2ts /path/clip1.m2ts -- /path/clip2.m2ts
15 // one title is built for each playlist
16 // playlist-0 is used as first-play item
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.
22 // if the first play item is the main title, that is ok also.
23 // ./brwrite /tmp/dir /path/title.m2ts
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/.
45 #include "arraylist.h"
47 #define BCTEXTLEN 1024
48 #define BLURAY_TS_PKTSZ 192L
52 #include "libavfilter/buffersrc.h"
53 #include "libavfilter/buffersink.h"
54 #include "libavformat/avformat.h"
55 #include "libavformat/avio.h"
56 #include "libavcodec/avcodec.h"
57 #include "libavfilter/avfilter.h"
58 #include "libavutil/avutil.h"
59 #include "libavutil/opt.h"
60 #include "libavutil/pixdesc.h"
61 #include "libswresample/swresample.h"
62 #include "libswscale/swscale.h"
75 BLURAY_APP_TYPE_MAIN_MOVIE = 1,
76 BLURAY_APP_TYPE_MAIN_TIMED_SLIDE_SHOW = 2,
77 BLURAY_APP_TYPE_MAIN_BROWSED_SLIDE_SHOW = 3,
78 BLURAY_APP_TYPE_SUBPATH_BROWSED_SLIDE_SHOW = 4,
79 BLURAY_APP_TYPE_SUBPATH_IG_MENU = 5,
80 BLURAY_APP_TYPE_SUBPATH_TEXT_SUBTITLE = 6,
81 BLURAY_APP_TYPE_SUBPATH_ELEMENTARY_STREAM = 7,
83 BLURAY_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
84 BLURAY_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
85 BLURAY_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
86 BLURAY_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
87 BLURAY_STREAM_TYPE_AUDIO_LPCM = 0x80,
88 BLURAY_STREAM_TYPE_AUDIO_AC3 = 0x81,
89 BLURAY_STREAM_TYPE_AUDIO_DTS = 0x82,
90 BLURAY_STREAM_TYPE_AUDIO_TRUHD = 0x83,
91 BLURAY_STREAM_TYPE_AUDIO_AC3PLUS = 0x84,
92 BLURAY_STREAM_TYPE_AUDIO_DTSHD = 0x85,
93 BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER = 0x86,
94 BLURAY_STREAM_TYPE_VIDEO_VC1 = 0xea,
95 BLURAY_STREAM_TYPE_VIDEO_H264 = 0x1b,
96 BLURAY_STREAM_TYPE_VIDEO_H264_MVC = 0x20,
97 BLURAY_STREAM_TYPE_SUB_PG = 0x90,
98 BLURAY_STREAM_TYPE_SUB_IG = 0x91,
99 BLURAY_STREAM_TYPE_SUB_TEXT = 0x92,
100 BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY = 0xa1,
101 BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY = 0xa2,
103 BLURAY_MARK_TYPE_ENTRY = 0x01,
104 BLURAY_MARK_TYPE_LINK = 0x02,
106 BLURAY_PLAYBACK_TYPE_SEQUENTIAL = 1,
107 BLURAY_PLAYBACK_TYPE_RANDOM = 2,
108 BLURAY_PLAYBACK_TYPE_SHUFFLE = 3,
110 BLURAY_VIDEO_FORMAT_480I = 1, // ITU-R BT.601-5
111 BLURAY_VIDEO_FORMAT_576I = 2, // ITU-R BT.601-4
112 BLURAY_VIDEO_FORMAT_480P = 3, // SMPTE 293M
113 BLURAY_VIDEO_FORMAT_1080I = 4, // SMPTE 274M
114 BLURAY_VIDEO_FORMAT_720P = 5, // SMPTE 296M
115 BLURAY_VIDEO_FORMAT_1080P = 6, // SMPTE 274M
116 BLURAY_VIDEO_FORMAT_576P = 7, // ITU-R BT.1358
118 BLURAY_VIDEO_RATE_24000_1001 = 1, // 23.976
119 BLURAY_VIDEO_RATE_24 = 2,
120 BLURAY_VIDEO_RATE_25 = 3,
121 BLURAY_VIDEO_RATE_30000_1001 = 4, // 29.97
122 BLURAY_VIDEO_RATE_50 = 6,
123 BLURAY_VIDEO_RATE_60000_1001 = 7, // 59.94
125 BLURAY_ASPECT_RATIO_4_3 = 2,
126 BLURAY_ASPECT_RATIO_16_9 = 3,
128 BLURAY_AUDIO_FORMAT_MONO = 1,
129 BLURAY_AUDIO_FORMAT_STEREO = 3,
130 BLURAY_AUDIO_FORMAT_MULTI_CHAN = 6,
131 BLURAY_AUDIO_FORMAT_COMBO = 12, // Stereo ac3/dts,
133 BLURAY_AUDIO_RATE_48 = 1,
134 BLURAY_AUDIO_RATE_96 = 4,
135 BLURAY_AUDIO_RATE_192 = 5,
136 BLURAY_AUDIO_RATE_192_COMBO = 12, // 48 or 96 ac3/dts, 192 mpl/dts-hd
137 BLURAY_AUDIO_RATE_96_COMBO = 14, // 48 ac3/dts, 96 mpl/dts-hd
138 BLURAY_TEXT_CHAR_CODE_UTF8 = 0x01,
139 BLURAY_TEXT_CHAR_CODE_UTF16BE = 0x02,
140 BLURAY_TEXT_CHAR_CODE_SHIFT_JIS = 0x03,
141 BLURAY_TEXT_CHAR_CODE_EUC_KR = 0x04,
142 BLURAY_TEXT_CHAR_CODE_GB18030_20001 = 0x05,
143 BLURAY_TEXT_CHAR_CODE_CN_GB = 0x06,
144 BLURAY_TEXT_CHAR_CODE_BIG5 = 0x07,
146 BLURAY_STILL_NONE = 0x00,
147 BLURAY_STILL_TIME = 0x01,
148 BLURAY_STILL_INFINITE = 0x02,
150 BLURAY_PG_TEXTST_STREAM = 0x01,
151 BLURAY_SECONDARY_VIDEO_STREAM = 0x02,
152 BLURAY_SECONDARY_AUDIO_STREAM = 0x03,
160 bs_file() { fp = 0; }
164 int open(const char *fn);
166 void write(uint32_t v, int n);
168 void padb(int n) { pad(n*8); }
169 int64_t posb() { return fpos; }
170 void posb(int64_t n);
171 int64_t pos() { return posb()*8 + len; }
172 void writeb(uint8_t * bp, int n);
173 void writeb(const char *cp, int n) {
174 writeb((uint8_t *) cp, n);
181 bs_length() { fpos = len = 0; }
182 void bs_len(bs_file &bs, int n) {
183 bs.write(len, n); fpos = bs.posb();
185 void bs_end(bs_file &bs) {
186 len = bs.posb() - fpos;
188 void bs_ofs(bs_file &bs, int n) {
189 bs.write(fpos-n/8, n);
193 class _bd_stream_info {
204 _bd_stream_info() { memset(this, 0, sizeof(*this)); }
205 ~_bd_stream_info() {}
208 class bd_stream_info : public _bd_stream_info {
214 class _bd_clip_info {
218 uint16_t still_time; /* seconds */
223 _bd_clip_info() { memset(this, 0, sizeof(*this)); }
227 class bd_clip_info : public _bd_clip_info {
229 ArrayList<bd_stream_info *> video_streams;
230 ArrayList<bd_stream_info *> audio_streams;
231 ArrayList<bd_stream_info *> pg_streams;
232 ArrayList<bd_stream_info *> ig_streams;
233 ArrayList<bd_stream_info *> sec_audio_streams;
234 ArrayList<bd_stream_info *> sec_video_streams;
238 video_streams.remove_all_objects();
239 audio_streams.remove_all_objects();
240 pg_streams.remove_all_objects();
241 ig_streams.remove_all_objects();
242 sec_audio_streams.remove_all_objects();
243 sec_video_streams.remove_all_objects();
247 class _bd_title_chapter {
255 _bd_title_chapter() { memset(this, 0, sizeof(*this)); }
256 ~_bd_title_chapter() {}
259 class bd_title_chapter : public _bd_title_chapter {
261 bd_title_chapter() {}
262 ~bd_title_chapter() {}
265 class _bd_title_mark {
274 _bd_title_mark() { memset(this, 0, sizeof(*this)); }
278 class bd_title_mark : public _bd_title_mark {
284 class _bd_title_info {
291 _bd_title_info() { memset(this, 0, sizeof(*this)); }
295 class bd_title_info : public _bd_title_info {
297 ArrayList<bd_clip_info *> clips;
298 ArrayList<bd_title_chapter *> chapters;
299 ArrayList<bd_title_mark *> marks;
303 clips.remove_all_objects();
304 chapters.remove_all_objects();
305 marks.remove_all_objects();
309 class _clpi_stc_seq {
312 uint32_t spn_stc_start;
313 uint32_t presentation_start_time;
314 uint32_t presentation_end_time;
316 _clpi_stc_seq() { memset(this, 0, sizeof(*this)); }
320 class clpi_stc_seq : public _clpi_stc_seq {
328 class _clpi_atc_seq {
330 uint32_t spn_atc_start;
331 uint8_t offset_stc_id;
333 _clpi_atc_seq() { memset(this, 0, sizeof(*this)); }
337 class clpi_atc_seq : public _clpi_atc_seq {
339 ArrayList<clpi_stc_seq *> stc_seq;
344 stc_seq.remove_all_objects();
348 class clpi_sequences : public bs_length,
349 public ArrayList<clpi_atc_seq *> {
354 ~clpi_sequences() { remove_all_objects(); }
357 class _clpi_ts_type {
362 _clpi_ts_type() { memset(this, 0, sizeof(*this)); }
366 class clpi_ts_type : public _clpi_ts_type {
372 class _clpi_atc_delta {
378 _clpi_atc_delta() { memset(this, 0, sizeof(*this)); }
379 ~_clpi_atc_delta() {}
382 class clpi_atc_delta : public _clpi_atc_delta {
394 _clpi_font() { memset(this, 0, sizeof(*this)); }
398 class clpi_font : public _clpi_font {
404 class clpi_font_info {
406 ArrayList<clpi_font *> font;
410 font.remove_all_objects();
414 class _clpi_clip_info {
416 uint8_t clip_stream_type;
417 uint8_t application_type;
418 uint8_t is_atc_delta;
419 uint32_t ts_recording_rate;
420 uint32_t num_source_packets;
422 _clpi_clip_info() { memset(this, 0, sizeof(*this)); }
423 ~_clpi_clip_info() {}
426 class clpi_clip_info : public bs_length, public _clpi_clip_info {
428 clpi_ts_type ts_type_info;
429 clpi_font_info font_info;
430 ArrayList<clpi_atc_delta *> atc_delta;
435 atc_delta.remove_all_objects();
439 class _clpi_prog_stream {
450 _clpi_prog_stream() { memset(this, 0, sizeof(*this)); }
451 ~_clpi_prog_stream() {}
454 class clpi_prog_stream : public bs_length, public _clpi_prog_stream {
458 clpi_prog_stream() {}
459 ~clpi_prog_stream() {}
462 class _clpi_ep_coarse {
468 _clpi_ep_coarse() { memset(this, 0, sizeof(*this)); }
469 ~_clpi_ep_coarse() {}
472 class clpi_ep_coarse : public _clpi_ep_coarse {
480 class _clpi_ep_fine {
482 uint8_t is_angle_change_point;
483 uint8_t i_end_position_offset;
487 _clpi_ep_fine() { memset(this, 0, sizeof(*this)); }
491 class clpi_ep_fine : public _clpi_ep_fine {
499 class _clpi_ep_map_entry {
501 uint8_t ep_stream_type;
502 uint32_t ep_map_stream_start_addr;
504 _clpi_ep_map_entry() { memset(this, 0, sizeof(*this)); }
505 ~_clpi_ep_map_entry() {}
508 class clpi_ep_map_entry : public _clpi_ep_map_entry {
512 ArrayList<clpi_ep_coarse *> coarse;
513 ArrayList<clpi_ep_fine *> fine;
514 int write(uint32_t ep_map_pos);
517 clpi_ep_map_entry(int id) { fine_start = 0; pid = id; }
518 ~clpi_ep_map_entry() {
519 coarse.remove_all_objects();
520 fine.remove_all_objects();
526 uint32_t spn_program_sequence_start;
528 _clpi_prog() { memset(this, 0, sizeof(*this)); }
532 class clpi_prog : public _clpi_prog {
534 ArrayList<clpi_prog_stream *> streams;
535 uint16_t program_map_pid;
538 clpi_prog(int pmt_pid) { program_map_pid = pmt_pid; }
539 ~clpi_prog() { streams.remove_all_objects(); }
542 class clpi_programs : public bs_length,
543 public ArrayList<clpi_prog *> {
548 ~clpi_programs() { remove_all_objects(); }
551 class clpi_extents : public bs_length,
552 public ArrayList<uint32_t> {
563 _clpi_cpi() { type = 0; }
567 class clpi_cpi : public bs_length, public _clpi_cpi,
568 public ArrayList<clpi_ep_map_entry *> {
573 ~clpi_cpi() { remove_all_objects(); }
578 unsigned int menu_call : 1;
579 unsigned int title_search : 1;
580 unsigned int chapter_search : 1;
581 unsigned int time_search : 1;
582 unsigned int skip_to_next_point : 1;
583 unsigned int skip_to_prev_point : 1;
584 unsigned int play_firstplay : 1;
585 unsigned int stop : 1;
586 unsigned int pause_on : 1;
587 unsigned int pause_off : 1;
588 unsigned int still_off : 1;
589 unsigned int forward : 1;
590 unsigned int backward : 1;
591 unsigned int resume : 1;
592 unsigned int move_up : 1;
593 unsigned int move_down : 1;
594 unsigned int move_left : 1;
595 unsigned int move_right : 1;
596 unsigned int select : 1;
597 unsigned int activate : 1;
598 unsigned int select_and_activate : 1;
599 unsigned int primary_audio_change : 1;
600 unsigned int reserved0 : 1;
601 unsigned int angle_change : 1;
602 unsigned int popup_on : 1;
603 unsigned int popup_off : 1;
604 unsigned int pg_enable_disable : 1;
605 unsigned int pg_change : 1;
606 unsigned int secondary_video_enable_disable : 1;
607 unsigned int secondary_video_change : 1;
608 unsigned int secondary_audio_enable_disable : 1;
609 unsigned int secondary_audio_change : 1;
610 unsigned int reserved1 : 1;
611 unsigned int pip_pg_change : 1;
615 memset(this, 0, sizeof(*this));
633 _mpls_stream() { memset(this, 0, sizeof(*this)); }
637 class mpls_stream : public _mpls_stream {
639 bs_length strm, code;
655 class mpls_stn : public bs_length, public _mpls_stn {
657 ArrayList<mpls_stream *> video;
658 ArrayList<mpls_stream *> audio;
659 ArrayList<mpls_stream *> pg;
660 ArrayList<mpls_stream *> ig;
661 ArrayList<mpls_stream *> secondary_audio;
662 ArrayList<mpls_stream *> secondary_video;
663 // Secondary audio specific fields
664 ArrayList<uint8_t> sa_primary_audio_ref;
665 // Secondary video specific fields
666 ArrayList<uint8_t> sv_secondary_audio_ref;
667 ArrayList<uint8_t> sv_pip_pg_ref;
672 video.remove_all_objects();
673 audio.remove_all_objects();
674 pg.remove_all_objects();
675 ig.remove_all_objects();
676 secondary_audio.remove_all_objects();
677 secondary_video.remove_all_objects();
687 _mpls_clip() { memset(this, 0, sizeof(*this)); }
691 class mpls_clip : public _mpls_clip {
693 mpls_clip() { strcpy(codec_id, "M2TS"); }
699 uint8_t is_multi_angle;
700 uint8_t connection_condition;
703 uint8_t random_access_flag;
706 uint8_t is_different_audio;
707 uint8_t is_seamless_angle;
709 _mpls_pi() { memset(this, 0, sizeof(*this)); }
713 class mpls_pi : public bs_length, public _mpls_pi {
716 ArrayList<mpls_clip *> clip;
723 clip.remove_all_objects();
731 uint16_t play_item_ref;
733 uint16_t entry_es_pid;
736 _mpls_plm() { memset(this, 0, sizeof(*this)); }
740 class mpls_plm : public _mpls_plm {
750 uint8_t playback_type;
751 uint16_t playback_count;
752 uint8_t random_access_flag;
753 uint8_t audio_mix_flag;
754 uint8_t lossless_bypass_flag;
756 _mpls_ai() { memset(this, 0, sizeof(*this)); }
760 class mpls_ai : public bs_length, public _mpls_ai {
771 uint8_t connection_condition;
772 uint8_t is_multi_clip;
775 uint16_t sync_play_item_id;
778 _mpls_sub_pi() { memset(this, 0, sizeof(*this)); }
782 class mpls_sub_pi : public bs_length, public _mpls_sub_pi {
784 ArrayList<mpls_clip *> clip;
789 clip.remove_all_objects();
798 _mpls_sub() { memset(this, 0, sizeof(*this)); }
802 class mpls_sub : public bs_length, public _mpls_sub {
804 ArrayList<mpls_sub_pi *> sub_play_item;
809 sub_play_item.remove_all_objects();
813 class _mpls_pip_data {
818 uint8_t scale_factor;
820 _mpls_pip_data() { memset(this, 0, sizeof(*this)); }
824 class mpls_pip_data : public _mpls_pip_data {
832 class _mpls_pip_metadata {
835 uint8_t secondary_video_ref;
836 uint8_t timeline_type;
837 uint8_t luma_key_flag;
838 uint8_t upper_limit_luma_key;
839 uint8_t trick_play_flag;
841 _mpls_pip_metadata() { memset(this, 0, sizeof(*this)); }
842 ~_mpls_pip_metadata() {}
845 class mpls_pip_metadata : public _mpls_pip_metadata {
847 ArrayList<mpls_pip_data *> data;
849 int write(uint32_t start_address);
850 mpls_pip_metadata() {}
851 ~mpls_pip_metadata() {
852 data.remove_all_objects();
862 _mpls_pl() { memset(this, 0, sizeof(*this)); }
866 class mpls_pl : public _mpls_pl {
869 bs_length play, mark, subx, pipm;
871 ArrayList<mpls_pi *> play_item;
872 ArrayList<mpls_sub *> sub_path;
873 ArrayList<mpls_plm *> play_mark;
874 // extension data (profile 5, version 2.4)
875 ArrayList<mpls_sub *> ext_sub_path;
876 // extension data (Picture-In-Picture metadata)
877 ArrayList<mpls_pip_metadata *> ext_pip_data;
880 int write_playlist();
881 int write_playlistmark();
882 int write_subpath_extension();
883 int write_pip_metadata_extension();
886 mpls_pl() { sig = 1; }
888 play_item.remove_all_objects();
889 sub_path.remove_all_objects();
890 play_mark.remove_all_objects();
891 ext_sub_path.remove_all_objects();
892 ext_pip_data.remove_all_objects();
898 uint32_t sequence_info_start_addr;
899 uint32_t program_info_start_addr;
900 uint32_t cpi_start_addr;
901 uint32_t clip_mark_start_addr;
902 uint32_t ext_data_start_addr;
904 _clpi_cl() { memset(this, 0, sizeof(*this)); }
908 class clpi_cl : public _clpi_cl {
912 clpi_sequences sequences;
913 clpi_programs programs;
915 clpi_extents extents;
916 clpi_programs programs_ss;
922 int write_clpi_extension(int id1, int id2, void *handle);
923 int write_mpls_extension(int id1, int id2, void *handle);
925 clpi_cl() { sig = 1; }
934 uint32_t sub_grp:3; /* command sub-group */
935 uint32_t grp:2; /* command group */
936 uint32_t op_cnt:3; /* operand count */
937 uint32_t branch_opt:4; /* branch option */
939 uint32_t imm_op2:1; /* I-flag for operand 2 */
940 uint32_t imm_op1:1; /* I-flag for operand 1 */
941 uint32_t cmp_opt:4; /* compare option */
943 uint32_t set_opt:5; /* set option */
950 command_obj() { cmd = dst = src = 0; }
956 int resume_intention_flag;
958 int title_search_mask;
960 _movie_obj() { memset(this, 0, sizeof(*this)); }
964 class movie_obj : public _movie_obj {
966 ArrayList<command_obj *> cmds;
970 cmds.remove_all_objects();
974 class movie_file : public bs_length {
977 ArrayList<movie_obj *> movies;
979 movie_file() { sig = 1; }
981 movies.remove_all_objects();
993 _pb_obj() { memset(this, 0, sizeof(*this)); }
997 class pb_obj : public _pb_obj {
1011 void set_hdmv(int id, int pt);
1012 void set_bdj(char *nm, int pt);
1013 void write_hdmv_obj(int id_ref);
1014 void write_bdj_obj(char *name);
1020 _title_obj() { acc_typ = 0; }
1024 class title_obj : public pb_obj, public _title_obj {
1035 int initial_output_mode_preference;
1036 int content_exist_flag;
1040 _index_file() { memset(this, 0, sizeof(*this)); }
1044 class index_file : public bs_length, public _index_file {
1046 ArrayList<title_obj *> titles;
1050 bs_length exten, appinf;
1052 void write_hdmv_obj(int hdmv_typ, int id_ref);
1053 void write_bdj_obj(int bdj_typ, char *name);
1054 void write_pb_obj(pb_obj * pb);
1059 memset(user_data, 0, sizeof(user_data));
1062 titles.remove_all_objects();
1068 uint32_t data_start;
1069 uint32_t extension_data_start;
1073 _bdid() { memset(this, 0, sizeof(*this)); }
1077 class bdid : public _bdid {
1086 class stream : public bd_stream_info {
1096 stream(AVMediaType ty, int i) {
1097 type = ty; av_idx = i;
1098 start_pts = INT64_MAX; end_pts = INT64_MIN;
1106 static int cmpr(mark **, mark **);
1107 int64_t sample, pos, pts;
1109 mark(int64_t s, int64_t p, int64_t ts, uint32_t pk, int id) {
1110 sample = s; pos = p; pts = ts; pkt = pk; pid = id;
1114 int mark::cmpr(mark **a, mark **b)
1116 mark *ap = *(mark **)a, *bp = *(mark **)b;
1117 return ap->pts > bp->pts ? 1 : ap->pts < bp->pts ? -1 : 0;
1122 int pmt_pid, pcr_pid, ep_pid;
1123 int64_t start_time, end_time;
1126 memset(this, 0, sizeof(*this));
1127 start_time = INT64_MAX; end_time = INT64_MIN;
1132 class program : public _program {
1136 ArrayList<int> strm_idx;
1137 ArrayList<mark*> marks;
1139 int build_toc(clpi_ep_map_entry *map);
1140 void add_label(uint32_t pk, int64_t p, int64_t ts, int id) {
1141 marks.append(new mark(curr_pos, p, ts, pk, id));
1144 program(int i, int id) { idx = i; pid = id; curr_pos = 0; }
1145 ~program() { marks.remove_all_objects(); }
1154 memset(this, 0, sizeof(*this));
1159 class media_info : public _media_info {
1161 static const AVRational clk45k;
1162 char filename[BCTEXTLEN];
1164 int brk, pidx, still;
1165 ArrayList<stream *> streams;
1166 ArrayList<program *> programs;
1167 program *prog() { return programs[pidx]; }
1169 media_info(const char *fn) {
1170 strcpy(filename, fn);
1171 brk = 0; pidx = 0; pgm_pid = -1; still = 0;
1174 streams.remove_all_objects();
1175 programs.remove_all_objects();
1179 int scan(AVFormatContext *fmt_ctx);
1182 class Media : public ArrayList<media_info *> {
1185 char filename[BCTEXTLEN];
1186 int bd_path(const char *bp, const char *fmt, va_list ap);
1187 int bd_open(const char *fmt, ...);
1188 int bd_backup(const char *fmt, ...);
1189 int bd_copy(const char *ifn, const char *fmt, ...);
1193 ArrayList<clpi_cl *> cl;
1194 ArrayList<mpls_pl *> pl;
1197 int write(char *fn);
1199 Media() { path = 0; filename[0] = 0; }
1201 remove_all_objects();
1202 cl.remove_all_objects();
1203 pl.remove_all_objects();
1209 void bs_file::init()
1217 bs_file::open(const char *fn)
1220 if( !fp ) perror(fn);
1221 return fp != 0 ? 0 : 1;
1227 if( fp ) { fclose(fp); fp = 0; }
1231 bs_file::write(uint32_t v, int n)
1238 if( fp ) fputc((vv >> len), fp);
1239 if( ++fpos > fsz ) fsz = fpos;
1244 bs_file::writeb(uint8_t * bp, int n)
1246 while( --n >= 0 ) write(*bp++, 8);
1252 while( n > 32 ) { write(0, 32); n -= 32; }
1253 if( n > 0 ) write(0, n);
1257 bs_file::posb(int64_t n)
1259 if( fpos == fsz && n > fpos ) {
1264 if( fp ) fseek(fp, fpos, SEEK_SET);
1274 bs.writeb("MOBJ", 4);
1275 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1276 int movie_start = 0x0028;
1277 bs.posb(movie_start);
1280 bs.write(movies.size(), 16);
1282 for (int i = 0; i < movies.size(); ++i) {
1283 movie_obj *mov = movies[i];
1284 bs.write(mov->resume_intention_flag, 1);
1285 bs.write(mov->menu_call_mask, 1);
1286 bs.write(mov->title_search_mask, 1);
1288 ArrayList<command_obj *> &cmds = mov->cmds;
1289 int num_cmds = cmds.size();
1290 bs.write(num_cmds, 16);
1291 for (int j = 0; j < num_cmds; ++j) {
1292 command_obj *cmd = cmds[j];
1293 bs.write(cmd->op_cnt, 3);
1294 bs.write(cmd->grp, 2);
1295 bs.write(cmd->sub_grp, 3);
1296 bs.write(cmd->imm_op1, 1);
1297 bs.write(cmd->imm_op2, 1);
1299 bs.write(cmd->branch_opt, 4);
1301 bs.write(cmd->cmp_opt, 4);
1303 bs.write(cmd->set_opt, 5);
1304 //bs.write(cmd->cmd, 32);
1305 bs.write(cmd->dst, 32);
1306 bs.write(cmd->src, 32);
1310 // bs.write('l', 8);
1311 // bs.writebcd(year, 16);
1312 // bs.writebcd(month, 8);
1313 // bs.writebcd(day, 8);
1314 // bs.writebcd(hour, 8);
1315 // bs.writebcd(min, 8);
1316 // bs.writebcd(sec, 8);
1322 pb_obj::set_hdmv(int id, int pt)
1332 pb_obj::set_bdj(char *nm, int pt)
1338 bdj_name = cstrdup(nm);
1342 pb_obj::write_hdmv_obj(int id_ref)
1344 bs.write(pb_typ, 2);
1346 bs.write(id_ref, 16);
1351 pb_obj::write_bdj_obj(char *name)
1353 bs.write(pb_typ, 2);
1364 write_bdj_obj(bdj_name);
1368 write_hdmv_obj(hdmv_id);
1374 title_obj::write_obj()
1376 bs.write(obj_typ, 2);
1377 bs.write(acc_typ, 2);
1379 pb_obj::write_obj();
1384 index_file::write_pb_obj(pb_obj * pb)
1386 bs.write(pb->obj_typ, 2);
1395 bs.writeb("INDX", 4);
1396 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1398 exten.bs_ofs(bs, 32);
1399 int appinfo_start = 0x28;
1400 bs.posb(appinfo_start);
1401 appinf.bs_len(bs, 32);
1403 bs.write(initial_output_mode_preference, 1);
1404 bs.write(content_exist_flag, 1);
1406 bs.write(video_format, 4);
1407 bs.write(frame_rate, 4);
1408 bs.writeb(user_data, 32);
1413 write_pb_obj(&first_play);
1414 write_pb_obj(&top_menu);
1415 bs.write(titles.size(), 16);
1417 for (int i = 0; i < titles.size(); ++i)
1418 titles[i]->write_obj();
1420 exten.bs_len(bs,32);
1430 bs.writeb("BDID",4);
1431 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1432 bs.write(data_start, 32);
1433 bs.write(extension_data_start, 32);
1435 bs.writeb(org_id, sizeof(org_id));
1436 bs.writeb(disc_id, sizeof(disc_id));
1440 // XXX - not current referenced
1443 bdmv_write_extension_data(int start_address,
1444 int (*handler) (int, int, void *), void *handle)
1449 bs.write(length, 32); /* length of extension data block */
1453 bs.pad(32); /* relative start address of extension data */
1454 bs.pad(24); /* padding */
1455 bs.write(num_entries, 8);
1457 for (n = 0; n < num_entries; n++) {
1460 bs.write(ext_start, 32);
1461 bs.write(ext_len, 32);
1462 saved_pos = bs.pos() >> 3;
1463 bs.posb(start_address + ext_start);
1464 handler(id1, id2, handle);
1473 clpi_prog_stream::write()
1478 bs.write(coding_type, 8);
1479 switch (coding_type) {
1480 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1481 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1482 case BLURAY_STREAM_TYPE_VIDEO_VC1:
1483 case BLURAY_STREAM_TYPE_VIDEO_H264:
1485 bs.write(format, 4);
1487 bs.write(aspect, 4);
1489 bs.write(oc_flag, 1);
1493 case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1494 case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1495 case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1496 case BLURAY_STREAM_TYPE_AUDIO_AC3:
1497 case BLURAY_STREAM_TYPE_AUDIO_DTS:
1498 case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1499 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1500 case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1501 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1502 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1503 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1504 bs.write(format, 4);
1509 case BLURAY_STREAM_TYPE_SUB_PG:
1510 case BLURAY_STREAM_TYPE_SUB_IG:
1515 case BLURAY_STREAM_TYPE_SUB_TEXT:
1516 bs.write(char_code, 8);
1521 fprintf(stderr, "clpi_prog_stream: unrecognized coding type %02x\n",
1531 clpi_cl::write_header()
1533 bs.writeb("HDMV", 4);
1534 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1535 bs.write(sequence_info_start_addr, 32);
1536 bs.write(program_info_start_addr, 32);
1537 bs.write(cpi_start_addr, 32);
1538 bs.write(clip_mark_start_addr, 32);
1539 bs.write(ext_data_start_addr, 32);
1544 clpi_atc_delta::write()
1546 bs.write(delta, 32);
1547 bs.writeb(file_id, 5);
1548 bs.writeb(file_code, 4);
1554 clpi_clip_info::write()
1559 bs.pad(16); // reserved
1560 bs.write(clip_stream_type, 8);
1561 bs.write(application_type, 8);
1562 bs.pad(31); // skip reserved 31 bits
1563 bs.write(is_atc_delta, 1);
1564 bs.write(ts_recording_rate, 32);
1565 bs.write(num_source_packets, 32);
1567 bs.padb(128); // Skip reserved 128 bytes
1569 // ts type info block
1571 bs.write(ts_len, 16);
1572 int64_t pos = bs.posb();
1574 bs.write(ts_type_info.validity, 8);
1575 bs.writeb(ts_type_info.format_id, 4);
1576 // pad the stuff we don't know anything about
1577 bs.padb(ts_len - (bs.posb() - pos));
1580 if( is_atc_delta ) {
1581 bs.pad(8); // Skip reserved byte
1582 bs.write(atc_delta.size(), 8);
1583 for( int ii=0; ii < atc_delta.size(); ++ii )
1584 if( atc_delta[ii]->write() ) return 1;
1588 if( application_type == 6 /* Sub TS for a sub-path of Text subtitle */ ) {
1590 bs.write(font_info.font.size(), 8);
1591 if( font_info.font.size() ) {
1592 for( int ii=0; ii < font_info.font.size(); ++ii ) {
1593 bs.writeb(font_info.font[ii]->file_id, 5);
1604 clpi_stc_seq::write()
1606 bs.write(pcr_pid, 16);
1607 bs.write(spn_stc_start, 32);
1608 bs.write(presentation_start_time, 32);
1609 bs.write(presentation_end_time, 32);
1614 clpi_atc_seq::write()
1616 bs.write(spn_atc_start, 32);
1617 bs.write(stc_seq.size(), 8);
1618 bs.write(offset_stc_id, 8);
1620 for( int ii=0; ii < stc_seq.size(); ++ii )
1621 if( stc_seq[ii]->write() ) return 1;
1626 clpi_sequences::write()
1629 bs.padb(1); // reserved byte
1630 bs.write(size(), 8);
1631 for( int ii=0; ii < size(); ++ii )
1632 if( get(ii)->write() ) return 1;
1640 bs.write(spn_program_sequence_start, 32);
1641 bs.write(program_map_pid, 16);
1642 bs.write(streams.size(), 8);
1643 bs.write(num_groups, 8);
1644 for( int ii=0; ii < streams.size(); ++ii )
1645 if( streams[ii]->write() ) return 1;
1650 clpi_programs::write()
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;
1662 clpi_ep_coarse::write()
1664 bs.write(ref_ep_fine_id, 18);
1665 bs.write(pts_ep, 14);
1666 bs.write(spn_ep, 32);
1671 clpi_ep_fine::write()
1673 bs.write(is_angle_change_point, 1);
1674 bs.write(i_end_position_offset, 3);
1675 bs.write(pts_ep, 11);
1676 bs.write(spn_ep, 17);
1681 clpi_ep_map_entry::write(uint32_t ep_map_pos)
1685 bs.write(ep_stream_type, 4);
1686 bs.write(coarse.size(), 16);
1687 bs.write(fine.size(), 18);
1688 bs.write(ep_map_stream_start_addr - ep_map_pos, 32);
1693 clpi_ep_map_entry::write_map()
1695 ep_map_stream_start_addr = bs.posb();
1696 bs.write(fine_start, 32);
1698 for( int ii=0; ii < coarse.size(); ++ii )
1699 if( coarse[ii]->write() ) return 1;
1701 fine_start = bs.posb() - ep_map_stream_start_addr;
1702 for( int ii=0; ii < fine.size(); ++ii )
1703 if( fine[ii]->write() ) return 1;
1714 uint32_t ep_map_pos = bs.posb();
1716 // EP Map starts here
1718 bs.write(size(), 8);
1720 for( int ii=0; ii < size(); ++ii )
1721 if( get(ii)->write(ep_map_pos) ) return 1;
1723 for( int ii=0; ii < size(); ++ii )
1724 if( get(ii)->write_map() ) return 1;
1731 clpi_extents::write()
1734 bs.write(size(), 32);
1735 for( int ii=0; ii < size(); ++ii )
1736 bs.write(get(ii), 32);
1741 clpi_cl::write_clpi_extension(int id1, int id2, void *handle)
1743 clpi_cl *cl = (clpi_cl *) handle;
1747 // LPCM down mix coefficient
1748 //write_lpcm_down_mix_coeff(&cl->lpcm_down_mix_coeff);
1755 // Extent start point
1756 return cl->extents.write();
1760 return cl->programs_ss.write();
1764 return cl->cpi_ss.write();
1768 fprintf(stderr, "write_clpi_extension(): unhandled extension %d.%d\n", id1, id2);
1775 if( write_header() ) return 1;
1776 if( clip.write() ) return 1;
1777 sequence_info_start_addr = bs.posb();
1778 if( sequences.write() ) return 1;
1779 program_info_start_addr = bs.posb();
1780 if( programs.write() ) return 1;
1781 cpi_start_addr = bs.posb();
1782 if( cpi.write() ) return 1;
1783 //if( has_ext_data ) {
1784 // ext_data_start_addr = bs.pos();
1785 // bdmv_write_extension_data(write_clpi_extension, this);
1793 bs.write(menu_call, 1);
1794 bs.write(title_search, 1);
1795 bs.write(chapter_search, 1);
1796 bs.write(time_search, 1);
1797 bs.write(skip_to_next_point, 1);
1798 bs.write(skip_to_prev_point, 1);
1799 bs.write(play_firstplay, 1);
1801 bs.write(pause_on, 1);
1802 bs.write(pause_off, 1);
1803 bs.write(still_off, 1);
1804 bs.write(forward, 1);
1805 bs.write(backward, 1);
1806 bs.write(resume, 1);
1807 bs.write(move_up, 1);
1808 bs.write(move_down, 1);
1809 bs.write(move_left, 1);
1810 bs.write(move_right, 1);
1811 bs.write(select, 1);
1812 bs.write(activate, 1);
1813 bs.write(select_and_activate, 1);
1814 bs.write(primary_audio_change, 1);
1816 bs.write(angle_change, 1);
1817 bs.write(popup_on, 1);
1818 bs.write(popup_off, 1);
1819 bs.write(pg_enable_disable, 1);
1820 bs.write(pg_change, 1);
1821 bs.write(secondary_video_enable_disable, 1);
1822 bs.write(secondary_video_change, 1);
1823 bs.write(secondary_audio_enable_disable, 1);
1824 bs.write(secondary_audio_change, 1);
1826 bs.write(pip_pg_change, 1);
1835 bs.pad(8); // Reserved
1836 bs.write(playback_type, 8);
1837 if (playback_type == BLURAY_PLAYBACK_TYPE_RANDOM ||
1838 playback_type == BLURAY_PLAYBACK_TYPE_SHUFFLE ) {
1839 bs.write(playback_count, 16);
1842 bs.pad(16); // Reserved
1845 bs.write(random_access_flag, 1);
1846 bs.write(audio_mix_flag, 1);
1847 bs.write(lossless_bypass_flag, 1);
1848 bs.pad(13); // Reserved
1854 mpls_pl::write_header()
1856 bs.writeb("MPLS", 4);
1857 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1858 bs.write(list_pos, 32);
1859 bs.write(mark_pos, 32);
1860 bs.write(ext_pos, 32);
1861 bs.pad(160); // Skip 160 reserved bits
1871 bs.write(stream_type, 8);
1872 switch (stream_type) {
1879 bs.write(subpath_id, 8);
1880 bs.write(subclip_id, 8);
1885 bs.write(subpath_id, 8);
1890 fprintf(stderr, "unrecognized stream type %02x\n", stream_type);
1896 bs.write(coding_type, 8);
1897 switch (coding_type) {
1898 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1899 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1900 case BLURAY_STREAM_TYPE_VIDEO_VC1:
1901 case BLURAY_STREAM_TYPE_VIDEO_H264:
1902 bs.write(format, 4);
1906 case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1907 case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1908 case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1909 case BLURAY_STREAM_TYPE_AUDIO_AC3:
1910 case BLURAY_STREAM_TYPE_AUDIO_DTS:
1911 case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1912 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1913 case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1914 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1915 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1916 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1917 bs.write(format, 4);
1922 case BLURAY_STREAM_TYPE_SUB_PG:
1923 case BLURAY_STREAM_TYPE_SUB_IG:
1927 case BLURAY_STREAM_TYPE_SUB_TEXT:
1928 bs.write(char_code, 8);
1933 fprintf(stderr, "mpls_stream: unrecognized coding type %02x\n", coding_type);
1944 bs.pad(16); // Skip 2 reserved bytes
1946 bs.write(video.size(), 8);
1947 bs.write(audio.size(), 8);
1948 bs.write(pg.size() - num_pip_pg, 8);
1949 bs.write(ig.size(), 8);
1950 bs.write(secondary_audio.size(), 8);
1951 bs.write(secondary_video.size(), 8);
1952 bs.write(num_pip_pg, 8);
1957 // Primary Video Streams
1958 for( int ii=0; ii < video.size(); ++ii )
1959 if( video[ii]->write() ) return 1;
1961 // Primary Audio Streams
1962 for( int ii=0; ii < audio.size(); ++ii )
1963 if( audio[ii]->write() ) return 1;
1965 // Presentation Graphic Streams
1966 for( int ii=0; ii < pg.size(); ++ii )
1967 if( pg[ii]->write() ) return 1;
1969 // Interactive Graphic Streams
1970 for( int ii=0; ii < ig.size(); ++ii )
1971 if( ig[ii]->write() ) return 1;
1973 // Secondary Audio Streams
1974 for( int ii=0; ii < secondary_audio.size(); ++ii ) {
1975 if( secondary_audio[ii]->write() ) return 1;
1976 // Read Secondary Audio Extra Attributes
1977 bs.write(sa_primary_audio_ref.size(), 8);
1979 for( int jj=0; jj < sa_primary_audio_ref.size(); ++jj )
1980 bs.write(sa_primary_audio_ref[jj], 8);
1981 if( sa_primary_audio_ref.size() % 2) bs.pad(8 );
1984 // Secondary Video Streams
1985 for( int ii=0; ii < secondary_video.size(); ++ii ) {
1986 if( secondary_video[ii]->write() ) return 1;
1987 // Read Secondary Video Extra Attributes
1988 bs.write(sv_secondary_audio_ref.size(), 8);
1990 for( int jj=0; jj < sv_secondary_audio_ref.size(); ++jj )
1991 bs.write(sv_secondary_audio_ref[jj], 8);
1992 if( sv_secondary_audio_ref.size() % 2) bs.pad(8 );
1993 bs.write(sv_pip_pg_ref.size(), 8);
1995 for( int jj=0; jj < sv_pip_pg_ref.size(); ++jj )
1996 bs.write(sv_pip_pg_ref[jj], 8);
1997 if( sv_pip_pg_ref.size() % 2) bs.pad(8 );
2008 // Primary Clip identifer
2009 bs.writeb(clip[0]->clip_id, 5);
2010 bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2011 bs.pad(11); // Skip reserved 11 bits
2013 bs.write(is_multi_angle, 1);
2014 bs.write(connection_condition, 4); // 0x01, 0x05, 0x06
2016 bs.write(clip[0]->stc_id, 8);
2017 bs.write(in_time, 32);
2018 bs.write(out_time, 32);
2021 bs.write(random_access_flag, 1);
2023 bs.write(still_mode, 8);
2024 if( still_mode == 0x01 ) {
2025 bs.write(still_time, 16);
2031 if( is_multi_angle ) {
2032 bs.write(clip.size(), 8);
2034 bs.write(is_different_audio, 1);
2035 bs.write(is_seamless_angle, 1);
2038 for( int ii=1; ii < clip.size(); ++ii ) {
2039 bs.writeb(clip[ii]->clip_id, 5);
2040 bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2041 bs.write(clip[ii]->stc_id, 8);
2044 if( stn.write() ) return 1;
2051 mpls_sub_pi::write()
2054 // Primary Clip identifer
2055 bs.writeb(clip[0]->clip_id, 5);
2056 bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2059 bs.write(connection_condition, 4); // 0x01, 0x05, 0x06
2061 bs.write(is_multi_clip, 1);
2062 bs.write(clip[0]->stc_id, 8);
2063 bs.write(in_time, 32);
2064 bs.write(out_time, 32);
2065 bs.write(sync_play_item_id, 16);
2066 bs.write(sync_pts, 32);
2069 bs.write(clip.size(), 8);
2071 for( int ii=1; ii < clip.size(); ++ii ) {
2072 // Primary Clip identifer
2073 bs.writeb(clip[ii]->clip_id, 5);
2074 bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2075 bs.write(clip[ii]->stc_id, 8);
2089 bs.write(is_repeat, 1);
2091 bs.write(sub_play_item.size(), 8);
2093 for( int ii=0; ii < sub_play_item.size(); ++ii )
2094 if( sub_play_item[ii]->write() ) return 1;
2103 bs.write(mark_id, 8);
2104 bs.write(mark_type, 8);
2105 bs.write(play_item_ref, 16);
2107 bs.write(entry_es_pid, 16);
2108 bs.write(duration, 32);
2113 mpls_pl::write_playlistmark()
2115 mark.bs_len(bs, 32);
2116 // Then get the number of marks
2117 bs.write(play_mark.size(), 16);
2119 for( int ii=0; ii < play_mark.size(); ++ii )
2120 if( play_mark[ii]->write() ) return 1;
2127 mpls_pl::write_playlist()
2131 // Skip reserved bytes
2134 bs.write(play_item.size(), 16);
2135 bs.write(sub_path.size(), 16);
2137 for( int ii=0; ii < play_item.size(); ++ii )
2138 if( play_item[ii]->write() ) return 1;
2140 for( int ii=0; ii < sub_path.size(); ++ii )
2141 if( sub_path[ii]->write() ) return 1;
2148 mpls_pip_data::write()
2153 bs.write(scale_factor, 4);
2159 mpls_pip_metadata::write(uint32_t start_address)
2162 bs.write(clip_ref, 16);
2163 bs.write(secondary_video_ref, 8);
2165 bs.write(timeline_type, 4);
2166 bs.write(luma_key_flag, 1);
2167 bs.write(trick_play_flag, 1);
2169 if( luma_key_flag ) {
2171 bs.write(upper_limit_luma_key, 8);
2178 uint32_t data_address = 0; // XXX
2179 bs.write(data_address, 32);
2181 int64_t pos = bs.pos() / 8;
2182 bs.posb(start_address + data_address);
2184 bs.write(data.size(), 16);
2185 if( data.size() < 1 ) return 1;
2187 for( int ii=0; ii < data.size(); ++ii )
2188 if( data[ii]->write() ) return 1;
2195 mpls_pl::write_pip_metadata_extension()
2197 uint32_t pos = bs.posb();
2198 pipm.bs_len(bs, 32);
2200 bs.write(ext_pip_data.size(), 16);
2201 for( int ii=0; ii < ext_pip_data.size(); ++ii )
2202 if( ext_pip_data[ii]->write(pos) ) return 1;
2209 mpls_pl::write_subpath_extension()
2211 subx.bs_len(bs, 32);
2213 bs.write(ext_sub_path.size(), 16);
2214 for( int ii=0; ii < ext_sub_path.size(); ++ii )
2215 if( ext_sub_path[ii]->write() ) return 1;
2222 clpi_cl::write_mpls_extension(int id1, int id2, void *handle)
2224 mpls_pl *pl = (mpls_pl *) handle;
2228 // PiP metadata extension
2229 return pl->write_pip_metadata_extension();
2238 // SubPath entries extension
2239 return pl->write_subpath_extension();
2249 int ret = write_header();
2250 list_pos = bs.posb();;
2251 if( !ret ) ret = write_playlist();
2252 mark_pos = bs.posb();
2253 if( !ret ) ret = write_playlistmark();
2254 //if( has_pls_extension ) {
2255 // ext_pos = bs.posb();
2256 // bdmv_write_extension_data(write_mpls_extension, pl);
2263 if( !mkdir(path, 0777) )
2270 mk_bdmv_dir(char *bdmv_path)
2272 if( mk_dir(bdmv_path) )
2274 char bdjo_path[BCTEXTLEN];
2275 sprintf(bdjo_path, "%s/BDJO", bdmv_path);
2276 if( mk_dir(bdjo_path) )
2278 char clipinf_path[BCTEXTLEN];
2279 sprintf(clipinf_path, "%s/CLIPINF", bdmv_path);
2280 if( mk_dir(clipinf_path) )
2282 char jar_path[BCTEXTLEN];
2283 sprintf(jar_path, "%s/JAR", bdmv_path);
2284 if( mk_dir(jar_path) )
2286 char playlist_path[BCTEXTLEN];
2287 sprintf(playlist_path, "%s/PLAYLIST", bdmv_path);
2288 if( mk_dir(playlist_path) )
2296 char bdmv_path[BCTEXTLEN];
2297 sprintf(bdmv_path, "%s/BDMV", path);
2298 if( mk_bdmv_dir(bdmv_path) ) return 1;
2299 char stream_path[BCTEXTLEN];
2300 sprintf(stream_path, "%s/BDMV/STREAM", path);
2301 if( mk_dir(stream_path) ) return 1;
2302 char auxdata_path[BCTEXTLEN];
2303 sprintf(auxdata_path, "%s/BDMV/AUXDATA", path);
2304 if( mk_dir(auxdata_path) ) return 1;
2305 char meta_path[BCTEXTLEN];
2306 sprintf(meta_path, "%s/BDMV/META", path);
2307 if( mk_dir(meta_path) ) return 1;
2308 char backup_path[BCTEXTLEN];
2309 sprintf(backup_path, "%s/BACKUP", bdmv_path);
2310 if( mk_bdmv_dir(backup_path) ) return 1;
2315 build_toc(clpi_ep_map_entry *map)
2317 clpi_ep_coarse *cp = 0;
2318 marks.sort(mark::cmpr);
2319 uint16_t ep_pid = map->pid;
2320 int64_t last_pts = -1, last_pkt = -1;
2321 for( int ii=0; ii<marks.size(); ++ii ) {
2322 mark *mp = marks[ii];
2323 if( mp->pid != ep_pid ) continue;
2324 int64_t pts = mp->pts;
2325 if( last_pts >= pts ) continue;
2327 uint32_t pkt = mp->pos / BLURAY_TS_PKTSZ;
2328 if( last_pkt >= pkt ) continue;
2330 int64_t coarse_pts = (pts >> 18) & ~0x01;
2331 int64_t fine_pts = (pts & 0x7ffff) >> 8;
2332 uint32_t mpkt = pkt & ~0x1ffff;
2333 if( !cp || cp->pts_ep != coarse_pts || cp->spn_ep != mpkt ) {
2334 cp = new clpi_ep_coarse();
2335 map->coarse.append(cp);
2336 cp->ref_ep_fine_id = map->fine.size();
2337 cp->pts_ep = coarse_pts;
2340 clpi_ep_fine *fp = new clpi_ep_fine();
2341 map->fine.append(fp);
2342 fp->is_angle_change_point = 0;
2343 // XXX - dont know what this is
2344 fp->i_end_position_offset = 1;
2345 fp->pts_ep = fine_pts;
2346 fp->spn_ep = pkt & 0x1ffff;
2351 const AVRational media_info::clk45k = { 1, 45000 };
2353 static int bd_stream_type(AVCodecID codec_id)
2355 int stream_type = 0;
2357 case AV_CODEC_ID_MPEG1VIDEO:
2358 case AV_CODEC_ID_MPEG2VIDEO:
2359 stream_type = BLURAY_STREAM_TYPE_VIDEO_MPEG2;
2361 case AV_CODEC_ID_H264:
2362 stream_type = BLURAY_STREAM_TYPE_VIDEO_H264;
2364 case AV_CODEC_ID_MP2:
2365 case AV_CODEC_ID_MP3:
2366 stream_type = BLURAY_STREAM_TYPE_AUDIO_MPEG1;
2368 case AV_CODEC_ID_AC3:
2369 stream_type = BLURAY_STREAM_TYPE_AUDIO_AC3;
2371 case AV_CODEC_ID_DTS:
2372 stream_type = BLURAY_STREAM_TYPE_AUDIO_DTS;
2374 case AV_CODEC_ID_TRUEHD:
2375 stream_type = BLURAY_STREAM_TYPE_AUDIO_TRUHD;
2378 fprintf(stderr, "unknown bluray stream type %s\n", avcodec_get_name(codec_id));
2384 static int bd_audio_format(int channels)
2386 int audio_format = 0;
2387 switch( channels ) {
2389 audio_format = BLURAY_AUDIO_FORMAT_MONO;
2392 audio_format = BLURAY_AUDIO_FORMAT_STEREO;
2395 audio_format = BLURAY_AUDIO_FORMAT_MULTI_CHAN;
2398 fprintf(stderr, "unknown bluray audio format %d ch\n", channels);
2401 return audio_format;
2404 static int bd_audio_rate(int rate)
2408 case 48000: audio_rate = BLURAY_AUDIO_RATE_48; break;
2409 case 96000: audio_rate = BLURAY_AUDIO_RATE_96; break;
2410 case 192000: audio_rate = BLURAY_AUDIO_RATE_192; break;
2412 fprintf(stderr, "unknown bluray audio rate %d\n", rate);
2418 static int bd_video_format(int w, int h, int ilace)
2420 if( w == 720 && h == 480 && ilace ) return BLURAY_VIDEO_FORMAT_480I;
2421 if( w == 720 && h == 576 && ilace ) return BLURAY_VIDEO_FORMAT_576I;
2422 if( w == 720 && h == 480 && !ilace ) return BLURAY_VIDEO_FORMAT_480P;
2423 if( w == 1920 && h == 1080 && ilace ) return BLURAY_VIDEO_FORMAT_1080I;
2424 if( w == 1280 && h == 720 && !ilace ) return BLURAY_VIDEO_FORMAT_720P;
2425 if( w == 1920 && h == 1080 && !ilace ) return BLURAY_VIDEO_FORMAT_1080P;
2426 if( w == 720 && h == 576 && !ilace ) return BLURAY_VIDEO_FORMAT_576P;
2427 fprintf(stderr, "unknown bluray video format %dx%d %silace\n",
2428 w, h, !ilace ? "not " : "");
2432 static int bd_video_rate(double rate)
2434 if( fabs(rate-23.976) < 0.01 ) return BLURAY_VIDEO_RATE_24000_1001;
2435 if( fabs(rate-24.000) < 0.01 ) return BLURAY_VIDEO_RATE_24;
2436 if( fabs(rate-25.000) < 0.01 ) return BLURAY_VIDEO_RATE_25;
2437 if( fabs(rate-29.970) < 0.01 ) return BLURAY_VIDEO_RATE_30000_1001;
2438 if( fabs(rate-50.000) < 0.01 ) return BLURAY_VIDEO_RATE_50;
2439 if( fabs(rate-59.940) < 0.01 ) return BLURAY_VIDEO_RATE_60000_1001;
2440 fprintf(stderr, "unknown bluray video framerate %5.2f\n",rate);
2444 static int bd_aspect_ratio(int w, double ratio)
2446 if( fabs(ratio-1.333) < 0.01 ) return BLURAY_ASPECT_RATIO_4_3;
2447 if( fabs(ratio-1.777) < 0.01 ) return BLURAY_ASPECT_RATIO_16_9;
2448 return w == 720 ? BLURAY_ASPECT_RATIO_4_3 : BLURAY_ASPECT_RATIO_16_9;
2449 fprintf(stderr, "unknown bluray aspect ratio %5.3f\n",ratio);
2453 int media_info::scan()
2456 if( stat(filename, &st) ) return 1;
2457 file_size = st.st_size;
2459 AVFormatContext *fmt_ctx = 0;
2460 AVDictionary *fopts = 0;
2461 av_dict_set(&fopts, "formatprobesize", "5000000", 0);
2462 av_dict_set(&fopts, "scan_all_pmts", "1", 0);
2463 av_dict_set(&fopts, "threads", "auto", 0);
2464 int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
2465 av_dict_free(&fopts);
2466 if( ret < 0 ) return ret;
2467 ret = avformat_find_stream_info(fmt_ctx, NULL);
2469 bit_rate = fmt_ctx->bit_rate;
2472 for( int i=0; ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
2473 AVStream *st = fmt_ctx->streams[i];
2474 AVMediaType type = st->codec->codec_type;
2476 case AVMEDIA_TYPE_VIDEO: break;
2477 case AVMEDIA_TYPE_AUDIO: break;
2480 stream *s = new stream(type, i);
2482 AVCodecID codec_id = st->codec->codec_id;
2484 case AVMEDIA_TYPE_VIDEO: {
2485 if( ep_pid < 0 ) ep_pid = st->id;
2486 s->coding_type = bd_stream_type(codec_id);
2487 s->format = bd_video_format(st->codec->width, st->codec->height,
2488 st->codec->flags & CODEC_FLAG_INTERLACED_ME);
2489 s->rate = bd_video_rate(!st->codec->framerate.den ? 0 :
2490 (double)st->codec->framerate.num / st->codec->framerate.den);
2491 s->aspect = bd_aspect_ratio(st->codec->width,!st->sample_aspect_ratio.den ? 0 :
2492 (double)st->sample_aspect_ratio.num / st->sample_aspect_ratio.den);
2494 case AVMEDIA_TYPE_AUDIO: {
2495 s->coding_type = bd_stream_type(codec_id);
2496 s->format = bd_audio_format(st->codec->channels);
2497 s->rate = bd_audio_rate(st->codec->sample_rate);
2498 strcpy((char*)s->lang, "und");
2503 if( bit_rate > 0 && st->duration == AV_NOPTS_VALUE &&
2504 st->time_base.num < INT64_MAX / bit_rate ) {
2505 st->duration = av_rescale(8*file_size, st->time_base.den,
2506 bit_rate * (int64_t) st->time_base.num);
2508 s->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2511 AVCodec *decoder = avcodec_find_decoder(codec_id);
2512 AVDictionary *copts = 0;
2513 ret = avcodec_open2(st->codec, decoder, &copts);
2516 ep_pid = fmt_ctx->nb_streams > 0 ? fmt_ctx->streams[0]->id : 0;
2518 int npgm = fmt_ctx->nb_programs;
2520 program *pgm = new program(-1, 1);
2521 pgm->ep_pid = ep_pid;
2522 pgm->pmt_pid = 0x1000;
2523 pgm->pcr_pid = 0x100;
2525 for( int jj=0; jj<streams.size(); ++jj ) {
2526 AVStream *st = fmt_ctx->streams[jj];
2527 AVMediaType type = st->codec->codec_type;
2529 case AVMEDIA_TYPE_VIDEO:
2530 case AVMEDIA_TYPE_AUDIO:
2535 pgm->strm_idx.append(jj);
2536 if( pgm->duration < st->duration )
2537 pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2539 programs.append(pgm);
2542 for( int ii=0; ii<npgm; ++ii ) {
2543 AVProgram *pgrm = fmt_ctx->programs[ii];
2544 program *pgm = new program(ii, pgrm->id);
2545 pgm->pmt_pid = pgrm->pmt_pid;
2546 pgm->pcr_pid = pgrm->pcr_pid;
2549 for( int jj=0; jj<(int)pgrm->nb_stream_indexes; ++jj ) {
2550 int av_idx = pgrm->stream_index[jj];
2551 AVStream *st = fmt_ctx->streams[av_idx];
2552 AVMediaType type = st->codec->codec_type;
2554 case AVMEDIA_TYPE_VIDEO:
2555 if( ep_pid < 0 ) ep_pid = st->id;
2557 case AVMEDIA_TYPE_AUDIO:
2562 int sidx = streams.size();
2563 while( --sidx>=0 && streams[sidx]->av_idx!=av_idx );
2565 fprintf(stderr, "bad stream idx %d in pgm %d\n",av_idx, ii);
2568 if( pgm->duration < st->duration )
2569 pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2570 pgm->strm_idx.append(sidx);
2573 AVProgram *pgrm = fmt_ctx->programs[0];
2574 ep_pid = pgrm->nb_stream_indexes > 0 ?
2575 fmt_ctx->streams[pgrm->stream_index[0]]->id : 0;
2577 pgm->ep_pid = ep_pid;
2578 programs.append(pgm);
2582 ret = scan(fmt_ctx);
2584 for( int i=0; i<(int)fmt_ctx->nb_streams; ++i )
2585 avcodec_close(fmt_ctx->streams[i]->codec);
2586 avformat_close_input(&fmt_ctx);
2591 int media_info::scan(AVFormatContext *fmt_ctx)
2595 av_init_packet(&ipkt);
2597 for( int64_t count=0; ret>=0; ++count ) {
2598 av_packet_unref(&ipkt);
2599 ipkt.data = 0; ipkt.size = 0;
2601 ret = av_read_frame(fmt_ctx, &ipkt);
2603 if( ret == AVERROR_EOF ) break;
2607 if( !ipkt.data ) continue;
2608 if( (ipkt.flags & AV_PKT_FLAG_CORRUPT) ) continue;
2609 if( ipkt.pts == AV_NOPTS_VALUE ) continue;
2610 int i = ipkt.stream_index;
2611 if( i < 0 || i >= streams.size() ) continue;
2615 for( int ii=0; !pgm && ii<programs.size(); ++ii ) {
2616 program *p = programs[ii];
2617 for( int jj=0; jj<p->strm_idx.size(); ++jj ) {
2618 sp = streams[p->strm_idx[jj]];
2619 if( sp->av_idx == i ) { pgm = p; break; }
2622 if( !pgm ) continue;
2623 AVStream *st = fmt_ctx->streams[i];
2624 if( pgm->ep_pid != st->id ) continue;
2625 int64_t pts45k = av_rescale_q(ipkt.pts, st->time_base, clk45k);
2626 if( sp->start_pts > pts45k ) sp->start_pts = pts45k;
2627 if( sp->end_pts < pts45k ) sp->end_pts = pts45k;
2628 if( pgm->start_time > pts45k ) pgm->start_time = pts45k;
2629 if( pgm->end_time < pts45k ) pgm->end_time = pts45k;
2631 if( !(ipkt.flags & AV_PKT_FLAG_KEY) ) continue;
2633 if( sp->last_pts != pts45k ) {
2634 sp->last_pts = pts45k;
2635 pgm->add_label(count, ipkt.pos, pts45k, st->id);
2639 for( int ii=0; ii<programs.size(); ++ii ) {
2640 program *pgm = programs[ii];
2641 if( pgm->end_time > pgm->start_time )
2642 pgm->duration = pgm->end_time - pgm->start_time;
2645 return ret != AVERROR_EOF ? -1 : 0;
2654 idx.first_play.set_hdmv(0, pb_typ_movie);
2655 idx.top_menu.set_hdmv(0xffff, pb_typ_iactv);
2660 movie_obj *mp = new movie_obj();
2661 mp->resume_intention_flag = 1;
2662 command_obj *cmd = new command_obj();
2663 cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
2664 mp->cmds.append(cmd); // JUMP_TITLE 1
2665 cmd = new command_obj();
2666 cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2667 mp->cmds.append(cmd);
2668 mov.movies.append(mp); // BREAK
2671 for( int ii=0; ii<size(); ++ii ) {
2672 mp = new movie_obj();
2673 mp->resume_intention_flag = 1;
2674 cmd = new command_obj();
2675 cmd->cmd = htobe32(0x22800000); cmd->dst = ii; cmd->src = 0;
2676 mp->cmds.append(cmd); // PLAY_PL ii
2677 cmd = new command_obj();
2678 cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2679 mp->cmds.append(cmd);
2680 mov.movies.append(mp); // BREAK
2683 mp = new movie_obj();
2684 mp->resume_intention_flag = 1;
2685 cmd = new command_obj();
2686 cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
2687 mp->cmds.append(cmd); // JUMP_TITLE 1
2688 cmd = new command_obj();
2689 cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2690 mp->cmds.append(cmd);
2691 mov.movies.append(mp); // BREAK
2695 for( int ii=0; ii<size(); ++ii ) {
2697 tp = new title_obj();
2698 tp->set_hdmv(idx.titles.size()+1, pb_typ_movie);
2699 idx.titles.append(tp);
2702 media_info *ip = get(ii);
2703 // clip program, if specified
2704 int pidx = ip->programs.size();
2705 while( --pidx>=0 && ip->programs[pidx]->pid != ip->pgm_pid );
2706 if( pidx < 0 ) pidx = 0;
2708 ip->pgm_pid = ip->prog()->pid;
2710 clpi_cl *cp = new clpi_cl();
2711 cp->clip.clip_stream_type = 1;
2712 cp->clip.application_type = BLURAY_APP_TYPE_MAIN_MOVIE;
2713 cp->clip.ts_recording_rate = ip->bit_rate;
2714 uint32_t ts_pkt_count = ip->file_size / BLURAY_TS_PKTSZ + 1;
2715 cp->clip.num_source_packets = ts_pkt_count;
2716 cp->clip.ts_type_info.validity = 0x80;
2717 strcpy(cp->clip.ts_type_info.format_id, "HDMV");
2720 for( int jj=0; jj<ip->programs.size(); ++jj ) {
2721 program *pgm = ip->programs[jj];
2722 clpi_prog *p = new clpi_prog(pgm->pmt_pid);
2723 for( int kk=0; kk<pgm->strm_idx.size(); ++kk ) {
2724 int k = pgm->strm_idx[kk];
2725 stream *sp = ip->streams[k];
2726 clpi_prog_stream *s = new clpi_prog_stream();
2728 s->coding_type = sp->coding_type;
2729 s->format = sp->format;
2730 //use unspecified (0)
2731 // if( !idx.video_format ) idx.video_format = s->format;
2733 // if( !idx.frame_rate ) idx.frame_rate = s->rate;
2734 switch( sp->type ) {
2735 case AVMEDIA_TYPE_VIDEO:
2736 s->aspect = sp->aspect;
2738 case AVMEDIA_TYPE_AUDIO:
2739 memcpy(s->lang,sp->lang,sizeof(s->lang));
2744 p->streams.append(s);
2746 clpi_ep_map_entry *map = new clpi_ep_map_entry(pgm->ep_pid);
2747 pgm->build_toc(map);
2748 cp->cpi.append(map);
2749 cp->programs.append(p);
2751 clpi_atc_seq *atc_seq = new clpi_atc_seq();
2752 clpi_stc_seq *stc_seq = new clpi_stc_seq();
2753 stc_seq->pcr_pid = pgm->pcr_pid;
2754 stc_seq->presentation_start_time = pgm->start_time;
2755 stc_seq->presentation_end_time = pgm->end_time;
2756 atc_seq->stc_seq.append(stc_seq);
2757 cp->sequences.append(atc_seq);
2762 if( ip->brk ) tp = 0;
2765 // playlists, one per title
2766 // one playitem per media clip
2768 for( int ii=0; ii<idx.titles.size(); ++ii ) {
2770 media_info *ip = get(clip_id);
2771 program *pgm = ip->prog();
2772 mpls_pl *pp = new mpls_pl();
2773 pp->app_info.playback_type = BLURAY_PLAYBACK_TYPE_SEQUENTIAL;
2774 // pp->app_info.uo_mask.xxx = 1;
2775 int last = idx.titles[ii]->last;
2776 for( ; clip_id<=last; ++clip_id ) {
2779 mpls_pi *pi = new mpls_pi();
2780 pi->connection_condition = 1; // seamless
2781 pi->in_time = pgm->start_time;
2782 pi->out_time = pgm->end_time;
2784 pi->still_mode = BLURAY_STILL_INFINITE;
2785 int64_t end_time = pgm->start_time + pgm->duration;
2786 if( pi->out_time < end_time ) pi->out_time = end_time;
2787 mpls_clip *cp = new mpls_clip();
2788 sprintf(cp->clip_id,"%05d", clip_id);
2789 pi->clip.append(cp);
2790 for( int kk=0; kk<ip->streams.size(); ++kk ) {
2791 stream *sp = ip->streams[kk];
2792 switch( sp->type ) {
2793 case AVMEDIA_TYPE_VIDEO: break;
2794 case AVMEDIA_TYPE_AUDIO: break;
2797 mpls_stream *ps = new mpls_stream();
2799 ps->stream_type = BLURAY_PG_TEXTST_STREAM;
2800 ps->coding_type = sp->coding_type;
2801 ps->format = sp->format;
2802 ps->rate = sp->rate;
2803 switch( sp->type ) {
2804 case AVMEDIA_TYPE_VIDEO:
2805 pi->stn.video.append(ps);
2807 case AVMEDIA_TYPE_AUDIO:
2808 memcpy(ps->lang, sp->lang, sizeof(ps->lang));
2809 pi->stn.audio.append(ps);
2815 pp->play_item.append(pi);
2817 // chapter marks every ch_duration ticks
2818 int64_t ch_duration = 45000 * 60*10;
2819 int64_t mrktm = ch_duration;
2821 int pmark = 0, pitem = 0;
2822 mpls_pi *pi = pp->play_item[pitem];
2823 mpls_plm *pm = new mpls_plm();
2824 pm->mark_id = pmark++;
2825 pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2826 pm->play_item_ref = pitem;
2827 pm->time = pi->in_time;
2828 pm->entry_es_pid = 0;
2829 pp->play_mark.append(pm);
2830 for( int jj=0; jj < pp->play_item.size(); ++jj ) {
2832 pi = pp->play_item[pitem];
2833 int64_t pi_duration = pi->out_time - pi->in_time;
2834 int64_t endtm = plytm + pi_duration;
2835 while( mrktm < endtm ) {
2836 pm = new mpls_plm();
2837 pm->mark_id = pmark++;
2838 pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2839 pm->play_item_ref = pitem;
2840 pm->time = pi->in_time + mrktm - plytm;
2841 pm->entry_es_pid = 0;
2842 pp->play_mark.append(pm);
2843 mrktm += ch_duration;
2847 pm = new mpls_plm();
2848 pm->mark_id = pmark;
2849 pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
2850 pm->play_item_ref = pitem;
2851 pm->time = pi->out_time;
2852 pm->entry_es_pid = 0;
2853 pp->play_mark.append(pm);
2861 bd_path(const char *bp, const char *fmt, va_list ap)
2863 int n = sizeof(filename)-1;
2864 char *cp = filename;
2865 const char *pp = path;
2866 while( n>0 && (*cp=*pp)!=0 ) { --n; ++cp; ++pp; }
2867 while( n>0 && (*cp=*bp)!=0 ) { --n; ++cp; ++bp; }
2868 n -= vsnprintf(cp, n, fmt, ap);
2870 return n > 0 ? 0 : 1;
2874 bd_copy(const char *ifn, const char *fmt, ...)
2878 FILE *ifp = fopen(ifn,"r");
2882 if( bd_path("/BDMV/", fmt, ap) ) return 1;
2884 FILE *ofp = fopen(filename,"w");
2886 setvbuf(ifp, 0, _IOFBF, 0x80000);
2887 setvbuf(ofp, 0, _IOFBF, 0x80000);
2888 while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
2895 fprintf(stderr, "cant copy clip %s\n",ifn);
2900 bd_open(const char *fmt, ...)
2903 if( !path ) return 0;
2906 if( bd_path("/BDMV/", fmt, ap) ) return 1;
2908 if( bs.open(filename) ) {
2909 fprintf(stderr, "cant open file %s\n",filename);
2916 bd_backup(const char *fmt, ...)
2919 if( !path ) return 0;
2922 FILE *ifp = fopen(filename,"r");
2926 if( bd_path("/BDMV/BACKUP/", fmt, ap) ) return 1;
2928 FILE *ofp = fopen(filename,"w");
2930 while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
2937 fprintf(stderr, "cant backup %s\n",filename);
2941 int Media::write(char *fn)
2945 if( bd_open("index.bdmv") ) return 1;
2946 if( idx.write() ) return 1;
2947 if( bd_backup("index.bdmv") ) return 1;
2949 if( bd_open("MovieObject.bdmv") ) return 1;
2950 if( mov.write() ) return 1;
2951 if( bd_backup("MovieObject.bdmv") ) return 1;
2953 for( int ii=0; ii<cl.size(); ++ii ) {
2954 if( bd_open("CLIPINF/%05d.clpi", ii) ) return 1;
2955 if( cl[ii]->write() ) return 1;
2956 if( bd_backup("CLIPINF/%05d.clpi", ii) ) return 1;
2959 for( int ii=0; ii<pl.size(); ++ii ) {
2960 if( bd_open("PLAYLIST/%05d.mpls", ii) ) return 1;
2961 if( pl[ii]->write() ) return 1;
2962 if( bd_backup("PLAYLIST/%05d.mpls", ii) ) return 1;
2968 main(int ac, char **av)
2971 if( mkbdmv(path) ) return 1;
2973 av_log_set_level(AV_LOG_FATAL);
2974 //av_log_set_level(AV_LOG_VERBOSE);
2975 //av_log_set_level(AV_LOG_DEBUG);
2979 for( int ii=2; ii<ac; ++ii ) {
2981 // any dash seq followed by number sets curr title pgm_pid
2982 // single dash only sets title pgm_pid
2983 // double dash ends curr title, starts a new title
2984 // triple dash ends curr title as infinite still
2987 if( *++ap == '-' ) {
2989 if( *++ap == '-' ) { ++ap; mp->still = 1; }
2991 if( *ap >= '0' && *ap <= '9' )
2992 mp->pgm_pid = strtoul(ap,&ap,0);
2993 if( mp->brk ) mp = 0;
2995 fprintf(stderr, "err arg %d: %s\n",ii,av[ii]);
3000 mp = new media_info(av[ii]);
3003 fprintf(stderr, "cant scan media: %s\n", av[ii]);
3008 if( mp ) mp->brk = 1;
3010 if( media.compose() ) {
3011 fprintf(stderr, "cant compose media\n");
3014 if( media.write(0) ) {
3015 fprintf(stderr, "cant prepare media\n");
3018 if( media.write(path) ) {
3019 fprintf(stderr, "cant write media\n");
3023 for( int ii=0; ii<media.size(); ++ii )
3024 if( media.bd_copy(media[ii]->filename, "STREAM/%05d.m2ts", ii) )