3 * Copyright (C) 2016-2020 William Morrow
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 //This program was created by inverting libbluray, without any docs,
23 // so it is probably got problems. Still, works on my Samsung player.
24 // thanks to: Petri Hintukainen, William Hahne, John Stebbinsm, et.al.
27 // ./bd <tgt_dir_path> <playlist-0> <sep> <playlistp1> <sep> ... <sep> <playlist-n>
28 // <sep> == -<pgm_pid> | --<pgm_pid> | ---<pgm_pid>
29 // <pgm_pid> may be empty string, or a numeric pgm_pid for curr title clip
30 // <pgm_pid> defaults to first pgm probed.
31 // <playlist-x> == <clip-0.m2ts> <clip-1.m2ts> ... <clip-n.m2ts>
33 // ./brwrite /tmp/dir /path/menu.m2ts --- /path/clip0.m2ts /path/clip1.m2ts -- /path/clip2.m2ts
35 // one title is built for each playlist
36 // playlist-0 is used as first-play item
38 // the basic idea is to use playlist-0 as a menu / directions to
39 // use the bluray player remote-control to select the desired title
40 // and start the play, avoiding the need for a menu system.
42 // if the first play item is the main title, that is ok also.
43 // ./brwrite /tmp/dir /path/title.m2ts
46 //To use a bluray bd-re rewriteable: (such as for /dev/sr1)
47 // dvd+rw-format /dev/sr1 (only done once to init the media)
48 // mkudffs /dev/sr1 $((`cat /sys/block/sr1/size`*512/2048-1))
49 // mount /dev/sr1 /mnt1
50 // cp -av <tgd_dir_path>/BDMV /mnt1/.
61 #if !defined (__FreeBSD__)
64 #include <sys/endian.h>
68 // work arounds (centos)
70 #define INT64_MAX 9223372036854775807LL
73 #define INT64_MIN (-INT64_MAX-1)
76 #include "arraylist.h"
78 #define BCTEXTLEN 1024
79 #define BLURAY_TS_PKTSZ 192L
81 static const int bd_sig = 2;
84 #include "libavfilter/buffersrc.h"
85 #include "libavfilter/buffersink.h"
86 #include "libavformat/avformat.h"
87 #include "libavformat/avio.h"
88 #include "libavcodec/avcodec.h"
89 #include "libavfilter/avfilter.h"
90 #include "libavutil/avutil.h"
91 #include "libavutil/opt.h"
92 #include "libavutil/pixdesc.h"
93 #include "libswresample/swresample.h"
94 #include "libswscale/swscale.h"
107 BLURAY_APP_TYPE_MAIN_MOVIE = 1,
108 BLURAY_APP_TYPE_MAIN_TIMED_SLIDE_SHOW = 2,
109 BLURAY_APP_TYPE_MAIN_BROWSED_SLIDE_SHOW = 3,
110 BLURAY_APP_TYPE_SUBPATH_BROWSED_SLIDE_SHOW = 4,
111 BLURAY_APP_TYPE_SUBPATH_IG_MENU = 5,
112 BLURAY_APP_TYPE_SUBPATH_TEXT_SUBTITLE = 6,
113 BLURAY_APP_TYPE_SUBPATH_ELEMENTARY_STREAM = 7,
115 BLURAY_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
116 BLURAY_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
117 BLURAY_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
118 BLURAY_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
119 BLURAY_STREAM_TYPE_AUDIO_LPCM = 0x80,
120 BLURAY_STREAM_TYPE_AUDIO_AC3 = 0x81,
121 BLURAY_STREAM_TYPE_AUDIO_DTS = 0x82,
122 BLURAY_STREAM_TYPE_AUDIO_TRUHD = 0x83,
123 BLURAY_STREAM_TYPE_AUDIO_AC3PLUS = 0x84,
124 BLURAY_STREAM_TYPE_AUDIO_DTSHD = 0x85,
125 BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER = 0x86,
126 BLURAY_STREAM_TYPE_VIDEO_VC1 = 0xea,
127 BLURAY_STREAM_TYPE_VIDEO_H264 = 0x1b,
128 BLURAY_STREAM_TYPE_VIDEO_H264_MVC = 0x20,
129 BLURAY_STREAM_TYPE_VIDEO_HEVC = 0x24,
130 BLURAY_STREAM_TYPE_SUB_PG = 0x90,
131 BLURAY_STREAM_TYPE_SUB_IG = 0x91,
132 BLURAY_STREAM_TYPE_SUB_TEXT = 0x92,
133 BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY = 0xa1,
134 BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY = 0xa2,
136 BLURAY_MARK_TYPE_ENTRY = 0x01,
137 BLURAY_MARK_TYPE_LINK = 0x02,
139 BLURAY_PLAYBACK_TYPE_SEQUENTIAL = 1,
140 BLURAY_PLAYBACK_TYPE_RANDOM = 2,
141 BLURAY_PLAYBACK_TYPE_SHUFFLE = 3,
143 BLURAY_VIDEO_FORMAT_480I = 1, // ITU-R BT.601-5
144 BLURAY_VIDEO_FORMAT_576I = 2, // ITU-R BT.601-4
145 BLURAY_VIDEO_FORMAT_480P = 3, // SMPTE 293M
146 BLURAY_VIDEO_FORMAT_1080I = 4, // SMPTE 274M
147 BLURAY_VIDEO_FORMAT_720P = 5, // SMPTE 296M
148 BLURAY_VIDEO_FORMAT_1080P = 6, // SMPTE 274M
149 BLURAY_VIDEO_FORMAT_576P = 7, // ITU-R BT.1358
150 BLURAY_VIDEO_FORMAT_2160P = 8,
152 BLURAY_VIDEO_RATE_24000_1001 = 1, // 23.976
153 BLURAY_VIDEO_RATE_24 = 2,
154 BLURAY_VIDEO_RATE_25 = 3,
155 BLURAY_VIDEO_RATE_30000_1001 = 4, // 29.97
156 BLURAY_VIDEO_RATE_50 = 6,
157 BLURAY_VIDEO_RATE_60000_1001 = 7, // 59.94
159 BLURAY_ASPECT_RATIO_4_3 = 2,
160 BLURAY_ASPECT_RATIO_16_9 = 3,
162 BLURAY_AUDIO_FORMAT_MONO = 1,
163 BLURAY_AUDIO_FORMAT_STEREO = 3,
164 BLURAY_AUDIO_FORMAT_MULTI_CHAN = 6,
165 BLURAY_AUDIO_FORMAT_COMBO = 12, // Stereo ac3/dts,
167 BLURAY_AUDIO_RATE_48 = 1,
168 BLURAY_AUDIO_RATE_96 = 4,
169 BLURAY_AUDIO_RATE_192 = 5,
170 BLURAY_AUDIO_RATE_192_COMBO = 12, // 48 or 96 ac3/dts, 192 mpl/dts-hd
171 BLURAY_AUDIO_RATE_96_COMBO = 14, // 48 ac3/dts, 96 mpl/dts-hd
172 BLURAY_TEXT_CHAR_CODE_UTF8 = 0x01,
173 BLURAY_TEXT_CHAR_CODE_UTF16BE = 0x02,
174 BLURAY_TEXT_CHAR_CODE_SHIFT_JIS = 0x03,
175 BLURAY_TEXT_CHAR_CODE_EUC_KR = 0x04,
176 BLURAY_TEXT_CHAR_CODE_GB18030_20001 = 0x05,
177 BLURAY_TEXT_CHAR_CODE_CN_GB = 0x06,
178 BLURAY_TEXT_CHAR_CODE_BIG5 = 0x07,
180 BLURAY_STILL_NONE = 0x00,
181 BLURAY_STILL_TIME = 0x01,
182 BLURAY_STILL_INFINITE = 0x02,
184 BLURAY_PG_TEXTST_STREAM = 0x01,
185 BLURAY_SECONDARY_VIDEO_STREAM = 0x02,
186 BLURAY_SECONDARY_AUDIO_STREAM = 0x03,
194 bs_file() { fp = 0; }
198 int open(const char *fn);
200 void write(uint32_t v, int n);
202 void padb(int n) { pad(n*8); }
203 int64_t posb() { return fpos; }
204 void posb(int64_t n);
205 int64_t pos() { return posb()*8 + len; }
206 void writeb(uint8_t * bp, int n);
207 void writeb(const char *cp, int n) {
208 writeb((uint8_t *) cp, n);
215 bs_length() { fpos = len = 0; }
216 int64_t bs_posb(bs_file &bs) { return bs.posb() - fpos; }
217 void bs_len(bs_file &bs, int n) {
218 bs.write(len, n); fpos = bs.posb();
220 void bs_end(bs_file &bs) {
223 void bs_ofs(bs_file &bs, int n) {
224 bs.write(fpos-n/8, n);
226 void bs_zofs(bs_file &bs, int n) {
227 bs.write(!len ? 0 : fpos-n/8, n);
231 class _bd_stream_info {
242 _bd_stream_info() { memset(this, 0, sizeof(*this)); }
243 ~_bd_stream_info() {}
246 class bd_stream_info : public _bd_stream_info {
252 class _bd_clip_info {
256 uint16_t still_time; /* seconds */
261 _bd_clip_info() { memset(this, 0, sizeof(*this)); }
265 class bd_clip_info : public _bd_clip_info {
267 ArrayList<bd_stream_info *> video_streams;
268 ArrayList<bd_stream_info *> audio_streams;
269 ArrayList<bd_stream_info *> pg_streams;
270 ArrayList<bd_stream_info *> ig_streams;
271 ArrayList<bd_stream_info *> sec_audio_streams;
272 ArrayList<bd_stream_info *> sec_video_streams;
276 video_streams.remove_all_objects();
277 audio_streams.remove_all_objects();
278 pg_streams.remove_all_objects();
279 ig_streams.remove_all_objects();
280 sec_audio_streams.remove_all_objects();
281 sec_video_streams.remove_all_objects();
285 class _bd_title_chapter {
293 _bd_title_chapter() { memset(this, 0, sizeof(*this)); }
294 ~_bd_title_chapter() {}
297 class bd_title_chapter : public _bd_title_chapter {
299 bd_title_chapter() {}
300 ~bd_title_chapter() {}
303 class _bd_title_mark {
312 _bd_title_mark() { memset(this, 0, sizeof(*this)); }
316 class bd_title_mark : public _bd_title_mark {
322 class _bd_title_info {
329 _bd_title_info() { memset(this, 0, sizeof(*this)); }
333 class bd_title_info : public _bd_title_info {
335 ArrayList<bd_clip_info *> clips;
336 ArrayList<bd_title_chapter *> chapters;
337 ArrayList<bd_title_mark *> marks;
341 clips.remove_all_objects();
342 chapters.remove_all_objects();
343 marks.remove_all_objects();
347 class _clpi_stc_seq {
350 uint32_t spn_stc_start;
351 uint32_t presentation_start_time;
352 uint32_t presentation_end_time;
354 _clpi_stc_seq() { memset(this, 0, sizeof(*this)); }
358 class clpi_stc_seq : public _clpi_stc_seq {
366 class _clpi_atc_seq {
368 uint32_t spn_atc_start;
369 uint8_t offset_stc_id;
371 _clpi_atc_seq() { memset(this, 0, sizeof(*this)); }
375 class clpi_atc_seq : public _clpi_atc_seq {
377 ArrayList<clpi_stc_seq *> stc_seq;
382 stc_seq.remove_all_objects();
386 class clpi_sequences : public bs_length,
387 public ArrayList<clpi_atc_seq *> {
392 ~clpi_sequences() { remove_all_objects(); }
395 class _clpi_ts_type {
400 _clpi_ts_type() { memset(this, 0, sizeof(*this)); }
404 class clpi_ts_type : public _clpi_ts_type {
410 class _clpi_atc_delta {
416 _clpi_atc_delta() { memset(this, 0, sizeof(*this)); }
417 ~_clpi_atc_delta() {}
420 class clpi_atc_delta : public _clpi_atc_delta {
432 _clpi_font() { memset(this, 0, sizeof(*this)); }
436 class clpi_font : public _clpi_font {
442 class clpi_font_info {
444 ArrayList<clpi_font *> font;
448 font.remove_all_objects();
452 class _clpi_clip_info {
454 uint8_t clip_stream_type;
455 uint8_t application_type;
456 uint8_t is_atc_delta;
457 uint32_t ts_recording_rate;
458 uint32_t num_source_packets;
460 _clpi_clip_info() { memset(this, 0, sizeof(*this)); }
461 ~_clpi_clip_info() {}
464 class clpi_clip_info : public bs_length, public _clpi_clip_info {
466 clpi_ts_type ts_type_info;
467 clpi_font_info font_info;
468 ArrayList<clpi_atc_delta *> atc_delta;
473 atc_delta.remove_all_objects();
477 class _clpi_prog_stream {
488 _clpi_prog_stream() { memset(this, 0, sizeof(*this)); }
489 ~_clpi_prog_stream() {}
492 class clpi_prog_stream : public bs_length, public _clpi_prog_stream {
496 clpi_prog_stream() {}
497 ~clpi_prog_stream() {}
500 class _clpi_ep_coarse {
506 _clpi_ep_coarse() { memset(this, 0, sizeof(*this)); }
507 ~_clpi_ep_coarse() {}
510 class clpi_ep_coarse : public _clpi_ep_coarse {
518 class _clpi_ep_fine {
520 uint8_t is_angle_change_point;
521 uint8_t i_end_position_offset;
525 _clpi_ep_fine() { memset(this, 0, sizeof(*this)); }
529 class clpi_ep_fine : public _clpi_ep_fine {
537 class _clpi_ep_map_entry {
539 uint8_t ep_stream_type;
540 uint32_t ep_map_stream_start_addr;
542 _clpi_ep_map_entry() { memset(this, 0, sizeof(*this)); }
543 ~_clpi_ep_map_entry() {}
546 class clpi_ep_map_entry : public _clpi_ep_map_entry {
550 ArrayList<clpi_ep_coarse *> coarse;
551 ArrayList<clpi_ep_fine *> fine;
552 int write(uint32_t ep_map_pos);
555 clpi_ep_map_entry(int id) { fine_start = 0; pid = id; }
556 ~clpi_ep_map_entry() {
557 coarse.remove_all_objects();
558 fine.remove_all_objects();
564 uint32_t spn_program_sequence_start;
566 _clpi_prog() { memset(this, 0, sizeof(*this)); }
570 class clpi_prog : public _clpi_prog {
572 ArrayList<clpi_prog_stream *> streams;
573 uint16_t program_map_pid;
576 clpi_prog(int pmt_pid) { program_map_pid = pmt_pid; }
577 ~clpi_prog() { streams.remove_all_objects(); }
580 class clpi_programs : public bs_length,
581 public ArrayList<clpi_prog *> {
586 ~clpi_programs() { remove_all_objects(); }
589 class clpi_extents : public bs_length,
590 public ArrayList<uint32_t> {
601 _clpi_cpi() { type = 0; }
605 class clpi_cpi : public bs_length, public _clpi_cpi,
606 public ArrayList<clpi_ep_map_entry *> {
611 ~clpi_cpi() { remove_all_objects(); }
614 class clpi_cmrk : public bs_length {
625 unsigned int menu_call : 1;
626 unsigned int title_search : 1;
627 unsigned int chapter_search : 1;
628 unsigned int time_search : 1;
629 unsigned int skip_to_next_point : 1;
630 unsigned int skip_to_prev_point : 1;
631 unsigned int play_firstplay : 1;
632 unsigned int stop : 1;
633 unsigned int pause_on : 1;
634 unsigned int pause_off : 1;
635 unsigned int still_off : 1;
636 unsigned int forward : 1;
637 unsigned int backward : 1;
638 unsigned int resume : 1;
639 unsigned int move_up : 1;
640 unsigned int move_down : 1;
641 unsigned int move_left : 1;
642 unsigned int move_right : 1;
643 unsigned int select : 1;
644 unsigned int activate : 1;
645 unsigned int select_and_activate : 1;
646 unsigned int primary_audio_change : 1;
647 unsigned int reserved0 : 1;
648 unsigned int angle_change : 1;
649 unsigned int popup_on : 1;
650 unsigned int popup_off : 1;
651 unsigned int pg_enable_disable : 1;
652 unsigned int pg_change : 1;
653 unsigned int secondary_video_enable_disable : 1;
654 unsigned int secondary_video_change : 1;
655 unsigned int secondary_audio_enable_disable : 1;
656 unsigned int secondary_audio_change : 1;
657 unsigned int reserved1 : 1;
658 unsigned int pip_pg_change : 1;
662 memset(this, 0, sizeof(*this));
677 uint8_t dynamic_range_type;
680 uint8_t hdr_plus_flag;
684 _mpls_stream() { memset(this, 0, sizeof(*this)); }
688 class mpls_stream : public _mpls_stream {
690 bs_length strm, code;
706 class mpls_stn : public bs_length, public _mpls_stn {
708 ArrayList<mpls_stream *> video;
709 ArrayList<mpls_stream *> audio;
710 ArrayList<mpls_stream *> pg;
711 ArrayList<mpls_stream *> ig;
712 ArrayList<mpls_stream *> secondary_audio;
713 ArrayList<mpls_stream *> secondary_video;
714 // Secondary audio specific fields
715 ArrayList<uint8_t> sa_primary_audio_ref;
716 // Secondary video specific fields
717 ArrayList<uint8_t> sv_secondary_audio_ref;
718 ArrayList<uint8_t> sv_pip_pg_ref;
723 video.remove_all_objects();
724 audio.remove_all_objects();
725 pg.remove_all_objects();
726 ig.remove_all_objects();
727 secondary_audio.remove_all_objects();
728 secondary_video.remove_all_objects();
738 _mpls_clip() { memset(this, 0, sizeof(*this)); }
742 class mpls_clip : public _mpls_clip {
744 mpls_clip() { strcpy(codec_id, "M2TS"); }
750 uint8_t is_multi_angle;
751 uint8_t connection_condition;
754 uint8_t random_access_flag;
757 uint8_t is_different_audio;
758 uint8_t is_seamless_angle;
760 _mpls_pi() { memset(this, 0, sizeof(*this)); }
764 class mpls_pi : public bs_length, public _mpls_pi {
767 ArrayList<mpls_clip *> clip;
774 clip.remove_all_objects();
782 uint16_t play_item_ref;
784 uint16_t entry_es_pid;
787 _mpls_plm() { memset(this, 0, sizeof(*this)); }
791 class mpls_plm : public _mpls_plm {
801 uint8_t playback_type;
802 uint16_t playback_count;
803 uint8_t random_access_flag;
804 uint8_t audio_mix_flag;
805 uint8_t lossless_bypass_flag;
807 _mpls_ai() { memset(this, 0, sizeof(*this)); }
811 class mpls_ai : public bs_length, public _mpls_ai {
822 uint8_t connection_condition;
823 uint8_t is_multi_clip;
826 uint16_t sync_play_item_id;
829 _mpls_sub_pi() { memset(this, 0, sizeof(*this)); }
833 class mpls_sub_pi : public bs_length, public _mpls_sub_pi {
835 ArrayList<mpls_clip *> clip;
840 clip.remove_all_objects();
849 _mpls_sub() { memset(this, 0, sizeof(*this)); }
853 class mpls_sub : public bs_length, public _mpls_sub {
855 ArrayList<mpls_sub_pi *> sub_play_item;
860 sub_play_item.remove_all_objects();
864 class _mpls_pip_data {
869 uint8_t scale_factor;
871 _mpls_pip_data() { memset(this, 0, sizeof(*this)); }
875 class mpls_pip_data : public _mpls_pip_data {
883 class _mpls_pip_metadata {
886 uint8_t secondary_video_ref;
887 uint8_t timeline_type;
888 uint8_t luma_key_flag;
889 uint8_t upper_limit_luma_key;
890 uint8_t trick_play_flag;
892 _mpls_pip_metadata() { memset(this, 0, sizeof(*this)); }
893 ~_mpls_pip_metadata() {}
896 class mpls_pip_metadata : public _mpls_pip_metadata {
898 ArrayList<mpls_pip_data *> data;
900 int write(uint32_t start_address);
901 mpls_pip_metadata() {}
902 ~mpls_pip_metadata() {
903 data.remove_all_objects();
913 _mpls_pl() { memset(this, 0, sizeof(*this)); }
917 class mpls_pl : public _mpls_pl {
920 bs_length play, mark, subx, pipm;
922 ArrayList<mpls_pi *> play_item;
923 ArrayList<mpls_sub *> sub_path;
924 ArrayList<mpls_plm *> play_mark;
925 // extension data (profile 5, version 2.4)
926 ArrayList<mpls_sub *> ext_sub_path;
927 // extension data (Picture-In-Picture metadata)
928 ArrayList<mpls_pip_metadata *> ext_pip_data;
931 int write_playlist();
932 int write_playlistmark();
933 int write_subpath_extension();
934 int write_pip_metadata_extension();
937 mpls_pl() { sig = bd_sig; }
939 play_item.remove_all_objects();
940 sub_path.remove_all_objects();
941 play_mark.remove_all_objects();
942 ext_sub_path.remove_all_objects();
943 ext_pip_data.remove_all_objects();
949 uint32_t sequence_info_start_addr;
950 uint32_t program_info_start_addr;
951 uint32_t cpi_start_addr;
952 uint32_t clip_mark_start_addr;
953 uint32_t ext_data_start_addr;
955 _clpi_cl() { memset(this, 0, sizeof(*this)); }
959 class clpi_cl : public _clpi_cl {
963 clpi_sequences sequences;
964 clpi_programs programs;
966 clpi_extents extents;
967 clpi_programs programs_ss;
974 int write_clpi_extension(int id1, int id2, void *handle);
975 int write_mpls_extension(int id1, int id2, void *handle);
977 clpi_cl() { sig = bd_sig; }
986 uint32_t sub_grp:3; /* command sub-group */
987 uint32_t grp:2; /* command group */
988 uint32_t op_cnt:3; /* operand count */
989 uint32_t branch_opt:4; /* branch option */
991 uint32_t imm_op2:1; /* I-flag for operand 2 */
992 uint32_t imm_op1:1; /* I-flag for operand 1 */
993 uint32_t cmp_opt:4; /* compare option */
995 uint32_t set_opt:5; /* set option */
1002 command_obj() { cmd = dst = src = 0; }
1008 int resume_intention_flag;
1010 int title_search_mask;
1012 _movie_obj() { memset(this, 0, sizeof(*this)); }
1016 class movie_obj : public _movie_obj {
1018 ArrayList<command_obj *> cmds;
1022 cmds.remove_all_objects();
1026 class movie_file : public bs_length {
1029 ArrayList<movie_obj *> movies;
1031 movie_file() { sig = bd_sig; }
1033 movies.remove_all_objects();
1045 _pb_obj() { memset(this, 0, sizeof(*this)); }
1049 class pb_obj : public _pb_obj {
1063 void set_hdmv(int id, int pt);
1064 void set_bdj(char *nm, int pt);
1065 void write_hdmv_obj(int id_ref);
1066 void write_bdj_obj(char *name);
1072 _title_obj() { acc_typ = 0; }
1076 class title_obj : public pb_obj, public _title_obj {
1087 int initial_output_mode_preference;
1088 int content_exist_flag;
1092 _index_file() { memset(this, 0, sizeof(*this)); }
1096 class index_file : public bs_length, public _index_file {
1098 ArrayList<title_obj *> titles;
1102 bs_length exten, appinf;
1104 void write_hdmv_obj(int hdmv_typ, int id_ref);
1105 void write_bdj_obj(int bdj_typ, char *name);
1106 void write_pb_obj(pb_obj * pb);
1111 memset(user_data, 0, sizeof(user_data));
1114 titles.remove_all_objects();
1120 uint32_t data_start;
1121 uint32_t extension_data_start;
1125 _bdid() { memset(this, 0, sizeof(*this)); }
1129 class bdid : public _bdid {
1134 bdid() { sig = bd_sig; }
1138 class stream : public bd_stream_info {
1143 AVCodecContext *ctx;
1149 stream(AVMediaType ty, int i) {
1150 type = ty; av_idx = i; ctx = 0;
1151 start_pts = INT64_MAX; end_pts = INT64_MIN;
1154 ~stream() { if( ctx ) avcodec_free_context(&ctx); }
1159 static int cmpr(mark **, mark **);
1160 int64_t sample, pos, pts;
1162 mark(int64_t s, int64_t p, int64_t ts, uint32_t pk, int id) {
1163 sample = s; pos = p; pts = ts; pkt = pk; pid = id;
1167 int mark::cmpr(mark **a, mark **b)
1169 mark *ap = *(mark **)a, *bp = *(mark **)b;
1170 return ap->pts > bp->pts ? 1 : ap->pts < bp->pts ? -1 : 0;
1175 int pmt_pid, pcr_pid, ep_pid;
1176 int64_t start_time, end_time;
1179 memset(this, 0, sizeof(*this));
1180 start_time = INT64_MAX; end_time = INT64_MIN;
1185 class program : public _program {
1189 ArrayList<int> strm_idx;
1190 ArrayList<mark*> marks;
1192 int build_toc(clpi_ep_map_entry *map);
1193 void add_label(uint32_t pk, int64_t p, int64_t ts, int id) {
1194 marks.append(new mark(curr_pos, p, ts, pk, id));
1197 program(int i, int id) { idx = i; pid = id; curr_pos = 0; }
1198 ~program() { marks.remove_all_objects(); }
1207 memset(this, 0, sizeof(*this));
1212 class media_info : public _media_info {
1214 static const AVRational clk45k;
1215 char filename[BCTEXTLEN];
1217 int brk, pidx, still;
1218 ArrayList<stream *> streams;
1219 ArrayList<program *> programs;
1220 program *prog() { return programs[pidx]; }
1222 media_info(const char *fn) {
1223 strcpy(filename, fn);
1224 brk = 0; pidx = 0; pgm_pid = -1; still = 0;
1227 streams.remove_all_objects();
1228 programs.remove_all_objects();
1232 int scan(AVFormatContext *fmt_ctx);
1235 class Media : public ArrayList<media_info *> {
1238 char filename[BCTEXTLEN];
1239 int bd_path(const char *bp, const char *fmt, va_list ap);
1240 int bd_open(const char *fmt, ...);
1241 int bd_backup(const char *fmt, ...);
1242 int bd_copy(const char *ifn, const char *fmt, ...);
1246 ArrayList<clpi_cl *> cl;
1247 ArrayList<mpls_pl *> pl;
1249 void add_movie(uint32_t *ops, int n);
1250 int compose(int ch_interval);
1251 int write(char *fn);
1253 Media() { path = 0; filename[0] = 0; }
1255 remove_all_objects();
1256 cl.remove_all_objects();
1257 pl.remove_all_objects();
1263 void bs_file::init()
1271 bs_file::open(const char *fn)
1274 if( !fp ) perror(fn);
1275 return fp != 0 ? 0 : 1;
1281 if( fp ) { fclose(fp); fp = 0; }
1285 bs_file::write(uint32_t v, int n)
1292 if( fp ) fputc((vv >> len), fp);
1293 if( ++fpos > fsz ) fsz = fpos;
1298 bs_file::writeb(uint8_t * bp, int n)
1300 while( --n >= 0 ) write(*bp++, 8);
1306 while( n > 32 ) { write(0, 32); n -= 32; }
1307 if( n > 0 ) write(0, n);
1311 bs_file::posb(int64_t n)
1313 if( fpos == fsz && n > fpos ) {
1318 if( fp ) fseek(fp, fpos, SEEK_SET);
1328 bs.writeb("MOBJ", 4);
1329 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1330 int movie_start = 0x0028;
1331 bs.posb(movie_start);
1334 bs.write(movies.size(), 16);
1336 for (int i = 0; i < movies.size(); ++i) {
1337 movie_obj *mov = movies[i];
1338 bs.write(mov->resume_intention_flag, 1);
1339 bs.write(mov->menu_call_mask, 1);
1340 bs.write(mov->title_search_mask, 1);
1342 ArrayList<command_obj *> &cmds = mov->cmds;
1343 int num_cmds = cmds.size();
1344 bs.write(num_cmds, 16);
1345 for (int j = 0; j < num_cmds; ++j) {
1346 command_obj *cmd = cmds[j];
1347 bs.write(cmd->op_cnt, 3);
1348 bs.write(cmd->grp, 2);
1349 bs.write(cmd->sub_grp, 3);
1350 bs.write(cmd->imm_op1, 1);
1351 bs.write(cmd->imm_op2, 1);
1353 bs.write(cmd->branch_opt, 4);
1355 bs.write(cmd->cmp_opt, 4);
1357 bs.write(cmd->set_opt, 5);
1358 //bs.write(cmd->cmd, 32);
1359 bs.write(cmd->dst, 32);
1360 bs.write(cmd->src, 32);
1364 // bs.write('l', 8);
1365 // bs.writebcd(year, 16);
1366 // bs.writebcd(month, 8);
1367 // bs.writebcd(day, 8);
1368 // bs.writebcd(hour, 8);
1369 // bs.writebcd(min, 8);
1370 // bs.writebcd(sec, 8);
1376 pb_obj::set_hdmv(int id, int pt)
1386 pb_obj::set_bdj(char *nm, int pt)
1392 bdj_name = cstrdup(nm);
1396 pb_obj::write_hdmv_obj(int id_ref)
1398 bs.write(pb_typ, 2);
1400 bs.write(id_ref, 16);
1405 pb_obj::write_bdj_obj(char *name)
1407 bs.write(pb_typ, 2);
1418 write_bdj_obj(bdj_name);
1422 write_hdmv_obj(hdmv_id);
1428 title_obj::write_obj()
1430 bs.write(obj_typ, 2);
1431 bs.write(acc_typ, 2);
1433 pb_obj::write_obj();
1438 index_file::write_pb_obj(pb_obj * pb)
1440 bs.write(pb->obj_typ, 2);
1449 bs.writeb("INDX", 4);
1450 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1452 exten.bs_zofs(bs, 32);
1453 int appinfo_start = 0x28;
1454 bs.posb(appinfo_start);
1455 appinf.bs_len(bs, 32);
1457 bs.write(initial_output_mode_preference, 1);
1458 bs.write(content_exist_flag, 1);
1460 bs.write(video_format, 4);
1461 bs.write(frame_rate, 4);
1462 bs.writeb(user_data, 32);
1467 write_pb_obj(&first_play);
1468 write_pb_obj(&top_menu);
1469 bs.write(titles.size(), 16);
1471 for (int i = 0; i < titles.size(); ++i)
1472 titles[i]->write_obj();
1474 exten.bs_len(bs,32);
1484 bs.writeb("BDID",4);
1485 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1486 bs.write(data_start, 32);
1487 bs.write(extension_data_start, 32);
1489 bs.writeb(org_id, sizeof(org_id));
1490 bs.writeb(disc_id, sizeof(disc_id));
1494 // XXX - not current referenced
1497 bdmv_write_extension_data(int start_address,
1498 int (*handler) (int, int, void *), void *handle)
1503 bs.write(length, 32); /* length of extension data block */
1507 bs.pad(32); /* relative start address of extension data */
1508 bs.pad(24); /* padding */
1509 bs.write(num_entries, 8);
1511 for (n = 0; n < num_entries; n++) {
1514 bs.write(ext_start, 32);
1515 bs.write(ext_len, 32);
1516 saved_pos = bs.pos() >> 3;
1517 bs.posb(start_address + ext_start);
1518 handler(id1, id2, handle);
1527 clpi_prog_stream::write()
1532 bs.write(coding_type, 8);
1533 switch (coding_type) {
1534 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1535 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1536 case BLURAY_STREAM_TYPE_VIDEO_VC1:
1537 case BLURAY_STREAM_TYPE_VIDEO_H264:
1538 case BLURAY_STREAM_TYPE_VIDEO_HEVC:
1540 bs.write(format, 4);
1542 bs.write(aspect, 4);
1544 bs.write(oc_flag, 1);
1548 case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1549 case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1550 case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1551 case BLURAY_STREAM_TYPE_AUDIO_AC3:
1552 case BLURAY_STREAM_TYPE_AUDIO_DTS:
1553 case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1554 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1555 case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1556 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1557 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1558 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1559 bs.write(format, 4);
1564 case BLURAY_STREAM_TYPE_SUB_PG:
1565 case BLURAY_STREAM_TYPE_SUB_IG:
1570 case BLURAY_STREAM_TYPE_SUB_TEXT:
1571 bs.write(char_code, 8);
1576 fprintf(stderr, "clpi_prog_stream: unrecognized coding type %02x\n",
1581 bs.padb(0x15 - bs_posb(bs));
1587 clpi_cl::write_header()
1589 bs.writeb("HDMV", 4);
1590 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1591 bs.write(sequence_info_start_addr, 32);
1592 bs.write(program_info_start_addr, 32);
1593 bs.write(cpi_start_addr, 32);
1594 bs.write(clip_mark_start_addr, 32);
1595 bs.write(ext_data_start_addr, 32);
1600 clpi_atc_delta::write()
1602 bs.write(delta, 32);
1603 bs.writeb(file_id, 5);
1604 bs.writeb(file_code, 4);
1610 clpi_clip_info::write()
1615 bs.pad(16); // reserved
1616 bs.write(clip_stream_type, 8);
1617 bs.write(application_type, 8);
1618 bs.pad(31); // skip reserved 31 bits
1619 bs.write(is_atc_delta, 1);
1620 bs.write(ts_recording_rate, 32);
1621 bs.write(num_source_packets, 32);
1623 bs.padb(128); // Skip reserved 128 bytes
1625 // ts type info block
1627 bs.write(ts_len, 16);
1628 int64_t pos = bs.posb();
1630 bs.write(ts_type_info.validity, 8);
1631 bs.writeb(ts_type_info.format_id, 4);
1632 // pad the stuff we don't know anything about
1633 bs.padb(ts_len - (bs.posb() - pos));
1636 if( is_atc_delta ) {
1637 bs.pad(8); // Skip reserved byte
1638 bs.write(atc_delta.size(), 8);
1639 for( int ii=0; ii < atc_delta.size(); ++ii )
1640 if( atc_delta[ii]->write() ) return 1;
1644 if( application_type == 6 /* Sub TS for a sub-path of Text subtitle */ ) {
1646 bs.write(font_info.font.size(), 8);
1647 if( font_info.font.size() ) {
1648 for( int ii=0; ii < font_info.font.size(); ++ii ) {
1649 bs.writeb(font_info.font[ii]->file_id, 5);
1660 clpi_stc_seq::write()
1662 bs.write(pcr_pid, 16);
1663 bs.write(spn_stc_start, 32);
1664 bs.write(presentation_start_time, 32);
1665 bs.write(presentation_end_time, 32);
1670 clpi_atc_seq::write()
1672 bs.write(spn_atc_start, 32);
1673 bs.write(stc_seq.size(), 8);
1674 bs.write(offset_stc_id, 8);
1676 for( int ii=0; ii < stc_seq.size(); ++ii )
1677 if( stc_seq[ii]->write() ) return 1;
1682 clpi_sequences::write()
1685 bs.padb(1); // reserved byte
1686 bs.write(size(), 8);
1687 for( int ii=0; ii < size(); ++ii )
1688 if( get(ii)->write() ) return 1;
1696 bs.write(spn_program_sequence_start, 32);
1697 bs.write(program_map_pid, 16);
1698 bs.write(streams.size(), 8);
1699 bs.write(num_groups, 8);
1700 for( int ii=0; ii < streams.size(); ++ii )
1701 if( streams[ii]->write() ) return 1;
1706 clpi_programs::write()
1709 bs.padb(1); // reserved byte
1710 bs.write(size(), 8);
1711 for( int ii=0; ii < size(); ++ii )
1712 if( get(ii)->write() ) return 1;
1718 clpi_ep_coarse::write()
1720 bs.write(ref_ep_fine_id, 18);
1721 bs.write(pts_ep, 14);
1722 bs.write(spn_ep, 32);
1727 clpi_ep_fine::write()
1729 bs.write(is_angle_change_point, 1);
1730 bs.write(i_end_position_offset, 3);
1731 bs.write(pts_ep, 11);
1732 bs.write(spn_ep, 17);
1737 clpi_ep_map_entry::write(uint32_t ep_map_pos)
1741 bs.write(ep_stream_type, 4);
1742 bs.write(coarse.size(), 16);
1743 bs.write(fine.size(), 18);
1744 bs.write(ep_map_stream_start_addr - ep_map_pos, 32);
1749 clpi_ep_map_entry::write_map()
1751 ep_map_stream_start_addr = bs.posb();
1752 bs.write(fine_start, 32);
1754 for( int ii=0; ii < coarse.size(); ++ii )
1755 if( coarse[ii]->write() ) return 1;
1757 fine_start = bs.posb() - ep_map_stream_start_addr;
1758 for( int ii=0; ii < fine.size(); ++ii )
1759 if( fine[ii]->write() ) return 1;
1770 uint32_t ep_map_pos = bs.posb();
1772 // EP Map starts here
1774 bs.write(size(), 8);
1776 for( int ii=0; ii < size(); ++ii )
1777 if( get(ii)->write(ep_map_pos) ) return 1;
1779 for( int ii=0; ii < size(); ++ii )
1780 if( get(ii)->write_map() ) return 1;
1795 clpi_extents::write()
1798 bs.write(size(), 32);
1799 for( int ii=0; ii < size(); ++ii )
1800 bs.write(get(ii), 32);
1805 clpi_cl::write_clpi_extension(int id1, int id2, void *handle)
1807 clpi_cl *cl = (clpi_cl *) handle;
1811 // LPCM down mix coefficient
1812 //write_lpcm_down_mix_coeff(&cl->lpcm_down_mix_coeff);
1819 // Extent start point
1820 return cl->extents.write();
1824 return cl->programs_ss.write();
1828 return cl->cpi_ss.write();
1832 fprintf(stderr, "write_clpi_extension(): unhandled extension %d.%d\n", id1, id2);
1839 if( write_header() ) return 1;
1840 if( clip.write() ) return 1;
1841 sequence_info_start_addr = bs.posb();
1842 if( sequences.write() ) return 1;
1843 program_info_start_addr = bs.posb();
1844 if( programs.write() ) return 1;
1845 cpi_start_addr = bs.posb();
1846 if( cpi.write() ) return 1;
1847 clip_mark_start_addr = bs.posb();
1848 if( cmrk.write() ) return 1;
1849 //if( has_ext_data ) {
1850 // ext_data_start_addr = bs.pos();
1851 // bdmv_write_extension_data(write_clpi_extension, this);
1859 bs.write(menu_call, 1);
1860 bs.write(title_search, 1);
1861 bs.write(chapter_search, 1);
1862 bs.write(time_search, 1);
1863 bs.write(skip_to_next_point, 1);
1864 bs.write(skip_to_prev_point, 1);
1865 bs.write(play_firstplay, 1);
1867 bs.write(pause_on, 1);
1868 bs.write(pause_off, 1);
1869 bs.write(still_off, 1);
1870 bs.write(forward, 1);
1871 bs.write(backward, 1);
1872 bs.write(resume, 1);
1873 bs.write(move_up, 1);
1874 bs.write(move_down, 1);
1875 bs.write(move_left, 1);
1876 bs.write(move_right, 1);
1877 bs.write(select, 1);
1878 bs.write(activate, 1);
1879 bs.write(select_and_activate, 1);
1880 bs.write(primary_audio_change, 1);
1882 bs.write(angle_change, 1);
1883 bs.write(popup_on, 1);
1884 bs.write(popup_off, 1);
1885 bs.write(pg_enable_disable, 1);
1886 bs.write(pg_change, 1);
1887 bs.write(secondary_video_enable_disable, 1);
1888 bs.write(secondary_video_change, 1);
1889 bs.write(secondary_audio_enable_disable, 1);
1890 bs.write(secondary_audio_change, 1);
1892 bs.write(pip_pg_change, 1);
1901 bs.pad(8); // Reserved
1902 bs.write(playback_type, 8);
1903 if (playback_type == BLURAY_PLAYBACK_TYPE_RANDOM ||
1904 playback_type == BLURAY_PLAYBACK_TYPE_SHUFFLE ) {
1905 bs.write(playback_count, 16);
1908 bs.pad(16); // Reserved
1911 bs.write(random_access_flag, 1);
1912 bs.write(audio_mix_flag, 1);
1913 bs.write(lossless_bypass_flag, 1);
1914 bs.pad(13); // Reserved
1920 mpls_pl::write_header()
1922 bs.writeb("MPLS", 4);
1923 bs.writeb(sig == 1 ? "0100" : "0200", 4);
1924 bs.write(list_pos, 32);
1925 bs.write(mark_pos, 32);
1926 bs.write(ext_pos, 32);
1927 bs.pad(160); // Skip 160 reserved bits
1937 bs.write(stream_type, 8);
1938 switch (stream_type) {
1945 bs.write(subpath_id, 8);
1946 bs.write(subclip_id, 8);
1951 bs.write(subpath_id, 8);
1956 fprintf(stderr, "unrecognized mpls stream type %02x\n", stream_type);
1959 bs.padb(9 - strm.bs_posb(bs));
1963 bs.write(coding_type, 8);
1964 switch (coding_type) {
1965 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
1966 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
1967 case BLURAY_STREAM_TYPE_VIDEO_VC1:
1968 case BLURAY_STREAM_TYPE_VIDEO_H264:
1969 case BLURAY_STREAM_TYPE_VIDEO_HEVC:
1970 bs.write(format, 4);
1974 case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
1975 case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
1976 case BLURAY_STREAM_TYPE_AUDIO_LPCM:
1977 case BLURAY_STREAM_TYPE_AUDIO_AC3:
1978 case BLURAY_STREAM_TYPE_AUDIO_DTS:
1979 case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
1980 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
1981 case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
1982 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
1983 case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
1984 case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
1985 bs.write(format, 4);
1990 case BLURAY_STREAM_TYPE_SUB_PG:
1991 case BLURAY_STREAM_TYPE_SUB_IG:
1995 case BLURAY_STREAM_TYPE_SUB_TEXT:
1996 bs.write(char_code, 8);
2001 fprintf(stderr, "mpls_stream: unrecognized coding type %02x\n", coding_type);
2004 bs.padb(5 - code.bs_posb(bs));
2013 bs.pad(16); // Skip 2 reserved bytes
2015 bs.write(video.size(), 8);
2016 bs.write(audio.size(), 8);
2017 bs.write(pg.size() - num_pip_pg, 8);
2018 bs.write(ig.size(), 8);
2019 bs.write(secondary_audio.size(), 8);
2020 bs.write(secondary_video.size(), 8);
2021 bs.write(num_pip_pg, 8);
2026 // Primary Video Streams
2027 for( int ii=0; ii < video.size(); ++ii )
2028 if( video[ii]->write() ) return 1;
2030 // Primary Audio Streams
2031 for( int ii=0; ii < audio.size(); ++ii )
2032 if( audio[ii]->write() ) return 1;
2034 // Presentation Graphic Streams
2035 for( int ii=0; ii < pg.size(); ++ii )
2036 if( pg[ii]->write() ) return 1;
2038 // Interactive Graphic Streams
2039 for( int ii=0; ii < ig.size(); ++ii )
2040 if( ig[ii]->write() ) return 1;
2042 // Secondary Audio Streams
2043 for( int ii=0; ii < secondary_audio.size(); ++ii ) {
2044 if( secondary_audio[ii]->write() ) return 1;
2045 // Read Secondary Audio Extra Attributes
2046 bs.write(sa_primary_audio_ref.size(), 8);
2048 for( int jj=0; jj < sa_primary_audio_ref.size(); ++jj )
2049 bs.write(sa_primary_audio_ref[jj], 8);
2050 if( sa_primary_audio_ref.size() % 2) bs.pad(8 );
2053 // Secondary Video Streams
2054 for( int ii=0; ii < secondary_video.size(); ++ii ) {
2055 if( secondary_video[ii]->write() ) return 1;
2056 // Read Secondary Video Extra Attributes
2057 bs.write(sv_secondary_audio_ref.size(), 8);
2059 for( int jj=0; jj < sv_secondary_audio_ref.size(); ++jj )
2060 bs.write(sv_secondary_audio_ref[jj], 8);
2061 if( sv_secondary_audio_ref.size() % 2) bs.pad(8 );
2062 bs.write(sv_pip_pg_ref.size(), 8);
2064 for( int jj=0; jj < sv_pip_pg_ref.size(); ++jj )
2065 bs.write(sv_pip_pg_ref[jj], 8);
2066 if( sv_pip_pg_ref.size() % 2) bs.pad(8 );
2077 // Primary Clip identifer
2078 bs.writeb(clip[0]->clip_id, 5);
2079 bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2080 bs.pad(11); // Skip reserved 11 bits
2082 bs.write(is_multi_angle, 1);
2083 bs.write(connection_condition, 4); // 0x01, 0x05, 0x06
2085 bs.write(clip[0]->stc_id, 8);
2086 bs.write(in_time, 32);
2087 bs.write(out_time, 32);
2090 bs.write(random_access_flag, 1);
2092 bs.write(still_mode, 8);
2093 if( still_mode == 0x01 ) {
2094 bs.write(still_time, 16);
2100 if( is_multi_angle ) {
2101 bs.write(clip.size(), 8);
2103 bs.write(is_different_audio, 1);
2104 bs.write(is_seamless_angle, 1);
2107 for( int ii=1; ii < clip.size(); ++ii ) {
2108 bs.writeb(clip[ii]->clip_id, 5);
2109 bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2110 bs.write(clip[ii]->stc_id, 8);
2113 if( stn.write() ) return 1;
2120 mpls_sub_pi::write()
2123 // Primary Clip identifer
2124 bs.writeb(clip[0]->clip_id, 5);
2125 bs.writeb(clip[0]->codec_id, 4); // "M2TS"
2128 bs.write(connection_condition, 4); // 0x01, 0x05, 0x06
2130 bs.write(is_multi_clip, 1);
2131 bs.write(clip[0]->stc_id, 8);
2132 bs.write(in_time, 32);
2133 bs.write(out_time, 32);
2134 bs.write(sync_play_item_id, 16);
2135 bs.write(sync_pts, 32);
2138 bs.write(clip.size(), 8);
2140 for( int ii=1; ii < clip.size(); ++ii ) {
2141 // Primary Clip identifer
2142 bs.writeb(clip[ii]->clip_id, 5);
2143 bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
2144 bs.write(clip[ii]->stc_id, 8);
2158 bs.write(is_repeat, 1);
2160 bs.write(sub_play_item.size(), 8);
2162 for( int ii=0; ii < sub_play_item.size(); ++ii )
2163 if( sub_play_item[ii]->write() ) return 1;
2172 bs.write(mark_id, 8);
2173 bs.write(mark_type, 8);
2174 bs.write(play_item_ref, 16);
2176 bs.write(entry_es_pid, 16);
2177 bs.write(duration, 32);
2182 mpls_pl::write_playlistmark()
2184 mark.bs_len(bs, 32);
2185 // Then get the number of marks
2186 bs.write(play_mark.size(), 16);
2188 for( int ii=0; ii < play_mark.size(); ++ii )
2189 if( play_mark[ii]->write() ) return 1;
2196 mpls_pl::write_playlist()
2200 // Skip reserved bytes
2203 bs.write(play_item.size(), 16);
2204 bs.write(sub_path.size(), 16);
2206 for( int ii=0; ii < play_item.size(); ++ii )
2207 if( play_item[ii]->write() ) return 1;
2209 for( int ii=0; ii < sub_path.size(); ++ii )
2210 if( sub_path[ii]->write() ) return 1;
2217 mpls_pip_data::write()
2222 bs.write(scale_factor, 4);
2228 mpls_pip_metadata::write(uint32_t start_address)
2231 bs.write(clip_ref, 16);
2232 bs.write(secondary_video_ref, 8);
2234 bs.write(timeline_type, 4);
2235 bs.write(luma_key_flag, 1);
2236 bs.write(trick_play_flag, 1);
2238 if( luma_key_flag ) {
2240 bs.write(upper_limit_luma_key, 8);
2247 uint32_t data_address = 0; // XXX
2248 bs.write(data_address, 32);
2250 int64_t pos = bs.pos() / 8;
2251 bs.posb(start_address + data_address);
2253 bs.write(data.size(), 16);
2254 if( data.size() < 1 ) return 1;
2256 for( int ii=0; ii < data.size(); ++ii )
2257 if( data[ii]->write() ) return 1;
2264 mpls_pl::write_pip_metadata_extension()
2266 uint32_t pos = bs.posb();
2267 pipm.bs_len(bs, 32);
2269 bs.write(ext_pip_data.size(), 16);
2270 for( int ii=0; ii < ext_pip_data.size(); ++ii )
2271 if( ext_pip_data[ii]->write(pos) ) return 1;
2278 mpls_pl::write_subpath_extension()
2280 subx.bs_len(bs, 32);
2282 bs.write(ext_sub_path.size(), 16);
2283 for( int ii=0; ii < ext_sub_path.size(); ++ii )
2284 if( ext_sub_path[ii]->write() ) return 1;
2291 clpi_cl::write_mpls_extension(int id1, int id2, void *handle)
2293 mpls_pl *pl = (mpls_pl *) handle;
2297 // PiP metadata extension
2298 return pl->write_pip_metadata_extension();
2307 // SubPath entries extension
2308 return pl->write_subpath_extension();
2318 int ret = write_header();
2319 list_pos = bs.posb();;
2320 if( !ret ) ret = write_playlist();
2321 mark_pos = bs.posb();
2322 if( !ret ) ret = write_playlistmark();
2323 //if( has_pls_extension ) {
2324 // ext_pos = bs.posb();
2325 // bdmv_write_extension_data(write_mpls_extension, pl);
2332 if( !mkdir(path, 0777) )
2339 mk_bdmv_dir(char *bdmv_path)
2341 if( mk_dir(bdmv_path) )
2343 char bdjo_path[BCTEXTLEN];
2344 sprintf(bdjo_path, "%s/BDJO", bdmv_path);
2345 if( mk_dir(bdjo_path) )
2347 char clipinf_path[BCTEXTLEN];
2348 sprintf(clipinf_path, "%s/CLIPINF", bdmv_path);
2349 if( mk_dir(clipinf_path) )
2351 char jar_path[BCTEXTLEN];
2352 sprintf(jar_path, "%s/JAR", bdmv_path);
2353 if( mk_dir(jar_path) )
2355 char playlist_path[BCTEXTLEN];
2356 sprintf(playlist_path, "%s/PLAYLIST", bdmv_path);
2357 if( mk_dir(playlist_path) )
2365 char bdmv_path[BCTEXTLEN];
2366 sprintf(bdmv_path, "%s/BDMV", path);
2367 if( mk_bdmv_dir(bdmv_path) ) return 1;
2368 char cert_path[BCTEXTLEN];
2369 sprintf(cert_path, "%s/CERTIFICATE", path);
2370 if( mk_bdmv_dir(cert_path) ) return 1;
2371 char cert_backup[BCTEXTLEN];
2372 sprintf(cert_backup, "%s/BACKUP", cert_path);
2373 if( mk_bdmv_dir(cert_backup) ) return 1;
2374 char stream_path[BCTEXTLEN];
2375 sprintf(stream_path, "%s/STREAM", bdmv_path);
2376 if( mk_dir(stream_path) ) return 1;
2377 char auxdata_path[BCTEXTLEN];
2378 sprintf(auxdata_path, "%s/AUXDATA", bdmv_path);
2379 if( mk_dir(auxdata_path) ) return 1;
2380 char meta_path[BCTEXTLEN];
2381 sprintf(meta_path, "%s/META", bdmv_path);
2382 if( mk_dir(meta_path) ) return 1;
2383 char backup_path[BCTEXTLEN];
2384 sprintf(backup_path, "%s/BACKUP", bdmv_path);
2385 if( mk_bdmv_dir(backup_path) ) return 1;
2390 build_toc(clpi_ep_map_entry *map)
2392 clpi_ep_coarse *cp = 0;
2393 marks.sort(mark::cmpr);
2394 uint16_t ep_pid = map->pid;
2395 int64_t last_pts = -1, last_pkt = -1;
2396 for( int ii=0; ii<marks.size(); ++ii ) {
2397 mark *mp = marks[ii];
2398 if( mp->pid != ep_pid ) continue;
2399 int64_t pts = mp->pts;
2400 if( last_pts >= pts ) continue;
2402 uint32_t pkt = mp->pos / BLURAY_TS_PKTSZ;
2403 if( last_pkt >= pkt ) continue;
2405 int64_t coarse_pts = (pts >> 18); // & ~0x01;
2406 int64_t fine_pts = (pts & 0x7ffff) >> 8;
2407 uint32_t mpkt = pkt & ~0x1ffff;
2408 if( !cp || cp->pts_ep != coarse_pts || mpkt > cp->spn_ep ) {
2409 cp = new clpi_ep_coarse();
2410 map->coarse.append(cp);
2411 cp->ref_ep_fine_id = map->fine.size();
2412 cp->pts_ep = coarse_pts;
2415 clpi_ep_fine *fp = new clpi_ep_fine();
2416 map->fine.append(fp);
2417 fp->is_angle_change_point = 0;
2418 // XXX - dont know what this is
2419 fp->i_end_position_offset = 1;
2420 fp->pts_ep = fine_pts;
2421 fp->spn_ep = pkt & 0x1ffff;
2426 const AVRational media_info::clk45k = { 1, 45000 };
2428 static int bd_coding_type(AVCodecID codec_id)
2430 int coding_type = 0;
2432 case AV_CODEC_ID_MPEG1VIDEO:
2433 coding_type = BLURAY_STREAM_TYPE_VIDEO_MPEG1;
2435 case AV_CODEC_ID_MPEG2VIDEO:
2436 coding_type = BLURAY_STREAM_TYPE_VIDEO_MPEG2;
2438 case AV_CODEC_ID_H264:
2439 coding_type = BLURAY_STREAM_TYPE_VIDEO_H264;
2441 case AV_CODEC_ID_HEVC:
2442 coding_type = BLURAY_STREAM_TYPE_VIDEO_HEVC;
2444 case AV_CODEC_ID_MP2:
2445 coding_type = BLURAY_STREAM_TYPE_AUDIO_MPEG1;
2447 case AV_CODEC_ID_MP3:
2448 coding_type = BLURAY_STREAM_TYPE_AUDIO_MPEG2;
2450 case AV_CODEC_ID_AC3:
2451 coding_type = BLURAY_STREAM_TYPE_AUDIO_AC3;
2453 case AV_CODEC_ID_EAC3:
2454 coding_type = BLURAY_STREAM_TYPE_AUDIO_AC3PLUS;
2456 case AV_CODEC_ID_DTS:
2457 coding_type = BLURAY_STREAM_TYPE_AUDIO_DTS;
2459 case AV_CODEC_ID_TRUEHD:
2460 coding_type = BLURAY_STREAM_TYPE_AUDIO_TRUHD;
2462 case AV_CODEC_ID_PCM_BLURAY:
2463 coding_type = BLURAY_STREAM_TYPE_AUDIO_LPCM;
2465 case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
2466 coding_type = BLURAY_STREAM_TYPE_SUB_PG;
2469 fprintf(stderr, "unknown bluray codec type %s\n", avcodec_get_name(codec_id));
2475 static int bd_audio_format(int channels)
2477 int audio_format = 0;
2478 switch( channels ) {
2480 audio_format = BLURAY_AUDIO_FORMAT_MONO;
2483 audio_format = BLURAY_AUDIO_FORMAT_STEREO;
2486 audio_format = BLURAY_AUDIO_FORMAT_MULTI_CHAN;
2489 fprintf(stderr, "unknown bluray audio format %d ch\n", channels);
2492 return audio_format;
2495 static int bd_audio_rate(int rate)
2499 case 48000: audio_rate = BLURAY_AUDIO_RATE_48; break;
2500 case 96000: audio_rate = BLURAY_AUDIO_RATE_96; break;
2501 case 192000: audio_rate = BLURAY_AUDIO_RATE_192; break;
2503 fprintf(stderr, "unknown bluray audio rate %d\n", rate);
2509 static int bd_video_format(int w, int h, int ilace)
2511 if( w == 720 && h == 480 && ilace ) return BLURAY_VIDEO_FORMAT_480I;
2512 if( w == 720 && h == 576 && ilace ) return BLURAY_VIDEO_FORMAT_576I;
2513 if( w == 720 && h == 480 && !ilace ) return BLURAY_VIDEO_FORMAT_480P;
2514 if( w == 720 && h == 576 && !ilace ) return BLURAY_VIDEO_FORMAT_576P;
2515 // this seems to be overly restrictive
2516 if( w == 1280 && h == 720 /* && !ilace*/ ) return BLURAY_VIDEO_FORMAT_720P;
2517 if( w == 1440 && h == 1080 /* && ilace*/ ) return BLURAY_VIDEO_FORMAT_1080I;
2518 if( w == 1920 && h == 1080 /* && !ilace*/ ) return BLURAY_VIDEO_FORMAT_1080P;
2519 if( w == 3840 && h == 2160 && !ilace ) return BLURAY_VIDEO_FORMAT_2160P;
2521 fprintf(stderr, "unknown bluray video format %dx%d %silace\n",
2522 w, h, !ilace ? "not " : "");
2526 static int bd_video_rate(double rate)
2528 if( fabs(rate-23.976) < 0.01 ) return BLURAY_VIDEO_RATE_24000_1001;
2529 if( fabs(rate-24.000) < 0.01 ) return BLURAY_VIDEO_RATE_24;
2530 if( fabs(rate-25.000) < 0.01 ) return BLURAY_VIDEO_RATE_25;
2531 if( fabs(rate-29.970) < 0.01 ) return BLURAY_VIDEO_RATE_30000_1001;
2532 if( fabs(rate-50.000) < 0.01 ) return BLURAY_VIDEO_RATE_50;
2533 if( fabs(rate-59.940) < 0.01 ) return BLURAY_VIDEO_RATE_60000_1001;
2534 fprintf(stderr, "unknown bluray video framerate %5.2f\n",rate);
2538 static int bd_aspect_ratio(int w, int h, double ratio)
2540 double aspect = (w * ratio) / h;
2541 if( fabs(aspect-1.333) < 0.01 ) return BLURAY_ASPECT_RATIO_4_3;
2542 if( fabs(aspect-1.777) < 0.01 ) return BLURAY_ASPECT_RATIO_16_9;
2543 return w == 720 ? BLURAY_ASPECT_RATIO_4_3 : BLURAY_ASPECT_RATIO_16_9;
2544 fprintf(stderr, "unknown bluray aspect ratio %5.3f\n",aspect);
2548 static int field_probe(AVFormatContext *fmt_ctx, AVStream *st)
2550 AVDictionary *copts = 0;
2551 //av_dict_copy(&copts, opts, 0);
2552 AVCodecID codec_id = st->codecpar->codec_id;
2553 #if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(58,134,100)
2554 AVCodec *decoder = avcodec_find_decoder(codec_id);
2556 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59,16,100)
2557 const AVCodec *decoder = avcodec_find_decoder(codec_id);
2559 AVCodecContext *ctx = avcodec_alloc_context3(decoder);
2561 fprintf(stderr,"codec alloc failed\n");
2564 avcodec_parameters_to_context(ctx, st->codecpar);
2565 if( avcodec_open2(ctx, decoder, &copts) < 0 ) {
2566 fprintf(stderr,"codec open failed\n");
2569 av_dict_free(&copts);
2571 AVFrame *ipic = av_frame_alloc();
2573 av_init_packet(&ipkt);
2575 for( int retrys=100; --retrys>=0 && ilaced<0; ) {
2576 av_packet_unref(&ipkt);
2577 int ret = av_read_frame(fmt_ctx, &ipkt);
2578 if( ret == AVERROR_EOF ) break;
2579 if( ret != 0 ) continue;
2580 if( ipkt.stream_index != st->index ) continue;
2581 if( !ipkt.data || !ipkt.size ) continue;
2582 ret = avcodec_send_packet(ctx, &ipkt);
2584 fprintf(stderr, "avcodec_send_packet failed\n");
2587 ret = avcodec_receive_frame(ctx, ipic);
2589 ilaced = ipic->interlaced_frame ? 1 : 0;
2592 if( ret != AVERROR(EAGAIN) )
2593 fprintf(stderr, "avcodec_receive_frame failed %d\n", ret);
2595 av_packet_unref(&ipkt);
2596 av_frame_free(&ipic);
2597 avcodec_free_context(&ctx);
2600 fprintf(stderr, "warning bdwrite uses field into from stream \n", st->codecpar->field_order);
2601 switch(st->codecpar->field_order) {
2607 case AV_FIELD_PROGRESSIVE:
2617 int media_info::scan()
2620 if( stat(filename, &st) ) return 1;
2621 file_size = st.st_size;
2623 AVFormatContext *fmt_ctx = 0;
2624 AVDictionary *fopts = 0;
2625 av_dict_set(&fopts, "formatprobesize", "5000000", 0);
2626 av_dict_set(&fopts, "scan_all_pmts", "1", 0);
2627 av_dict_set(&fopts, "threads", "auto", 0);
2628 int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
2629 av_dict_free(&fopts);
2630 if( ret < 0 ) return ret;
2631 ret = avformat_find_stream_info(fmt_ctx, NULL);
2633 bit_rate = fmt_ctx->bit_rate;
2636 for( int i=0; ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
2637 AVStream *st = fmt_ctx->streams[i];
2638 AVMediaType type = st->codecpar->codec_type;
2640 case AVMEDIA_TYPE_VIDEO: break;
2641 case AVMEDIA_TYPE_AUDIO: break;
2642 case AVMEDIA_TYPE_SUBTITLE: break;
2645 stream *s = new stream(type, i);
2647 AVCodecID codec_id = st->codecpar->codec_id;
2648 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59,16,100)
2649 const AVCodec *decoder = avcodec_find_decoder(codec_id);
2651 #if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(58,134,100)
2652 AVCodec *decoder = avcodec_find_decoder(codec_id);
2655 s->ctx = avcodec_alloc_context3(decoder);
2657 fprintf(stderr, "avcodec_alloc_context failed\n");
2661 case AVMEDIA_TYPE_VIDEO: {
2662 if( ep_pid < 0 ) ep_pid = st->id;
2663 s->coding_type = bd_coding_type(codec_id);
2664 int ilace = field_probe(fmt_ctx, st);
2666 fprintf(stderr, "interlace probe failed\n");
2669 s->format = bd_video_format(st->codecpar->width, st->codecpar->height, ilace);
2670 AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0);
2671 s->rate = bd_video_rate(!framerate.den ? 0 : (double)framerate.num / framerate.den);
2672 s->aspect = bd_aspect_ratio(st->codecpar->width, st->codecpar->height,
2673 !st->sample_aspect_ratio.num || !st->sample_aspect_ratio.den ? 1. :
2674 (double)st->sample_aspect_ratio.num / st->sample_aspect_ratio.den);
2676 case AVMEDIA_TYPE_AUDIO: {
2677 s->coding_type = bd_coding_type(codec_id);
2678 s->format = bd_audio_format(st->codecpar->ch_layout.nb_channels);
2679 s->rate = bd_audio_rate(st->codecpar->sample_rate);
2680 strcpy((char*)s->lang, "eng");
2682 case AVMEDIA_TYPE_SUBTITLE: {
2683 s->coding_type = bd_coding_type(codec_id);
2684 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", 0, 0);
2685 strncpy((char*)s->lang, lang ? lang->value : "und", sizeof(s->lang));
2690 if( bit_rate > 0 && st->duration == AV_NOPTS_VALUE &&
2691 st->time_base.num < INT64_MAX / bit_rate ) {
2692 st->duration = av_rescale(8*file_size, st->time_base.den,
2693 bit_rate * (int64_t) st->time_base.num);
2695 s->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2698 AVDictionary *copts = 0;
2699 ret = avcodec_open2(s->ctx, decoder, &copts);
2702 ep_pid = fmt_ctx->nb_streams > 0 ? fmt_ctx->streams[0]->id : 0;
2704 int npgm = fmt_ctx->nb_programs;
2706 program *pgm = new program(-1, 1);
2707 pgm->ep_pid = ep_pid;
2708 pgm->pmt_pid = 0x1000;
2709 pgm->pcr_pid = 0x1001;
2711 for( int jj=0; jj<streams.size(); ++jj ) {
2712 AVStream *st = fmt_ctx->streams[jj];
2713 AVMediaType type = st->codecpar->codec_type;
2715 case AVMEDIA_TYPE_VIDEO:
2716 case AVMEDIA_TYPE_AUDIO:
2721 pgm->strm_idx.append(jj);
2722 if( !pgm->duration || st->duration < pgm->duration )
2723 pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2725 programs.append(pgm);
2728 for( int ii=0; ii<npgm; ++ii ) {
2729 AVProgram *pgrm = fmt_ctx->programs[ii];
2730 program *pgm = new program(ii, pgrm->id);
2731 pgm->pmt_pid = pgrm->pmt_pid;
2732 pgm->pcr_pid = pgrm->pcr_pid;
2735 for( int jj=0; jj<(int)pgrm->nb_stream_indexes; ++jj ) {
2736 int av_idx = pgrm->stream_index[jj];
2737 AVStream *st = fmt_ctx->streams[av_idx];
2738 AVMediaType type = st->codecpar->codec_type;
2740 case AVMEDIA_TYPE_VIDEO:
2741 if( ep_pid < 0 ) ep_pid = st->id;
2743 case AVMEDIA_TYPE_AUDIO:
2744 case AVMEDIA_TYPE_SUBTITLE:
2749 int sidx = streams.size();
2750 while( --sidx>=0 && streams[sidx]->av_idx!=av_idx );
2752 fprintf(stderr, "bad stream idx %d in pgm %d\n",av_idx, ii);
2755 if( !pgm->duration || st->duration < pgm->duration )
2756 pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
2757 pgm->strm_idx.append(sidx);
2760 AVProgram *pgrm = fmt_ctx->programs[0];
2761 ep_pid = pgrm->nb_stream_indexes > 0 ?
2762 fmt_ctx->streams[pgrm->stream_index[0]]->id : 0;
2764 pgm->ep_pid = ep_pid;
2765 programs.append(pgm);
2769 ret = scan(fmt_ctx);
2771 for( int i=0; i<(int)streams.size(); ++i )
2772 avcodec_close(streams[i]->ctx);
2773 avformat_close_input(&fmt_ctx);
2778 int media_info::scan(AVFormatContext *fmt_ctx)
2782 av_init_packet(&ipkt);
2784 // zero pts at pos zero
2785 for( int i=0; i<programs.size(); ++i ) {
2786 program *p = programs[i];
2787 for( int j=0; j<p->strm_idx.size(); ++j ) {
2788 stream *sp = streams[p->strm_idx[j]];
2790 AVStream *st = fmt_ctx->streams[sp->av_idx];
2791 p->add_label(0, 0, 0, st->id);
2795 for( int64_t count=0; ret>=0; ++count ) {
2796 av_packet_unref(&ipkt);
2797 ipkt.data = 0; ipkt.size = 0;
2799 ret = av_read_frame(fmt_ctx, &ipkt);
2801 if( ret == AVERROR_EOF ) break;
2805 if( !ipkt.data ) continue;
2806 if( (ipkt.flags & AV_PKT_FLAG_CORRUPT) ) continue;
2807 if( ipkt.pts == AV_NOPTS_VALUE ) continue;
2808 int i = ipkt.stream_index;
2809 if( i < 0 || i >= streams.size() ) continue;
2813 for( int ii=0; !pgm && ii<programs.size(); ++ii ) {
2814 program *p = programs[ii];
2815 for( int jj=0; jj<p->strm_idx.size(); ++jj ) {
2816 sp = streams[p->strm_idx[jj]];
2817 if( sp->av_idx == i ) { pgm = p; break; }
2820 if( !pgm ) continue;
2821 AVStream *st = fmt_ctx->streams[i];
2822 if( pgm->ep_pid != st->id ) continue;
2823 int64_t pts45k = av_rescale_q(ipkt.pts, st->time_base, clk45k);
2824 if( sp->start_pts > pts45k ) sp->start_pts = pts45k;
2825 if( sp->end_pts < pts45k ) sp->end_pts = pts45k;
2826 if( pgm->start_time > pts45k ) pgm->start_time = pts45k;
2827 if( pgm->end_time < pts45k ) pgm->end_time = pts45k;
2829 if( !(ipkt.flags & AV_PKT_FLAG_KEY) ) continue;
2831 if( sp->last_pts != pts45k ) {
2832 sp->last_pts = pts45k;
2833 pgm->add_label(count, ipkt.pos, pts45k, st->id);
2837 for( int ii=0; ii<programs.size(); ++ii ) {
2838 program *pgm = programs[ii];
2839 if( pgm->end_time > pgm->start_time )
2840 pgm->duration = pgm->end_time - pgm->start_time;
2843 return ret != AVERROR_EOF ? -1 : 0;
2847 Media::add_movie(uint32_t *ops, int n)
2849 movie_obj *mp = new movie_obj();
2850 mp->resume_intention_flag = 1;
2851 uint32_t *eop = ops + n/sizeof(*ops);
2852 while( ops < eop ) {
2853 command_obj *cmd = new command_obj();
2854 cmd->cmd = htobe32(*ops++);
2857 mp->cmds.append(cmd);
2859 mov.movies.append(mp);
2863 Media::compose(int ch_interval)
2869 int top_menu_obj = mov.movies.size();
2870 movie_obj *mp = new movie_obj();
2871 mp->resume_intention_flag = 1;
2872 command_obj *cmd = new command_obj();
2873 cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
2874 mp->cmds.append(cmd); // JUMP_TITLE 1
2875 mov.movies.append(mp);
2878 for( int ii=0; ii<size(); ++ii ) {
2879 mp = new movie_obj();
2880 mp->resume_intention_flag = 1;
2881 cmd = new command_obj();
2882 cmd->cmd = htobe32(0x22800000); cmd->dst = ii; cmd->src = 0;
2883 mp->cmds.append(cmd); // PLAY_PL ii
2884 cmd = new command_obj();
2885 cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
2886 mp->cmds.append(cmd);
2887 mov.movies.append(mp); // BREAK
2891 int first_play_obj = mov.movies.size();
2892 mp = new movie_obj();
2893 mp->resume_intention_flag = 1;
2894 cmd = new command_obj();
2895 cmd->cmd = htobe32(0x21810000); cmd->dst = 0; cmd->src = 0;
2896 mp->cmds.append(cmd); // JUMP_TITLE 0 ; top menu
2897 mov.movies.append(mp);
2901 idx.first_play.set_hdmv(first_play_obj, pb_typ_iactv);
2902 idx.top_menu.set_hdmv(top_menu_obj, pb_typ_iactv);
2906 for( int ii=0; ii<size(); ++ii ) {
2908 tp = new title_obj();
2909 tp->set_hdmv(idx.titles.size()+1, pb_typ_movie);
2910 idx.titles.append(tp);
2913 media_info *ip = get(ii);
2914 // clip program, if specified
2915 int pidx = ip->programs.size();
2916 while( --pidx>=0 && ip->programs[pidx]->pid != ip->pgm_pid );
2917 if( pidx < 0 ) pidx = 0;
2919 ip->pgm_pid = ip->prog()->pid;
2921 clpi_cl *cp = new clpi_cl();
2922 cp->clip.clip_stream_type = 1;
2923 cp->clip.application_type = BLURAY_APP_TYPE_MAIN_MOVIE;
2924 cp->clip.ts_recording_rate = ip->bit_rate;
2925 uint32_t ts_pkt_count = ip->file_size / BLURAY_TS_PKTSZ;
2926 cp->clip.num_source_packets = ts_pkt_count;
2927 cp->clip.ts_type_info.validity = 0x80;
2928 strcpy(cp->clip.ts_type_info.format_id, "HDMV");
2931 for( int jj=0; jj<ip->programs.size(); ++jj ) {
2932 program *pgm = ip->programs[jj];
2933 clpi_prog *p = new clpi_prog(pgm->pmt_pid);
2934 for( int kk=0; kk<pgm->strm_idx.size(); ++kk ) {
2935 int k = pgm->strm_idx[kk];
2936 stream *sp = ip->streams[k];
2937 clpi_prog_stream *s = new clpi_prog_stream();
2939 s->coding_type = sp->coding_type;
2940 s->format = sp->format;
2941 //use unspecified (0)
2942 // if( !idx.video_format ) idx.video_format = s->format;
2944 // if( !idx.frame_rate ) idx.frame_rate = s->rate;
2945 switch( sp->type ) {
2946 case AVMEDIA_TYPE_VIDEO:
2947 s->aspect = sp->aspect;
2949 case AVMEDIA_TYPE_AUDIO:
2950 case AVMEDIA_TYPE_SUBTITLE:
2951 memcpy(s->lang,sp->lang,sizeof(s->lang));
2956 p->streams.append(s);
2958 clpi_ep_map_entry *map = new clpi_ep_map_entry(pgm->ep_pid);
2959 map->ep_stream_type = 1;
2960 pgm->build_toc(map);
2961 cp->cpi.append(map);
2962 cp->programs.append(p);
2964 clpi_atc_seq *atc_seq = new clpi_atc_seq();
2965 clpi_stc_seq *stc_seq = new clpi_stc_seq();
2966 stc_seq->pcr_pid = pgm->pcr_pid;
2967 stc_seq->presentation_start_time = pgm->start_time;
2968 stc_seq->presentation_end_time = pgm->end_time;
2969 atc_seq->stc_seq.append(stc_seq);
2970 cp->sequences.append(atc_seq);
2975 if( ip->brk ) tp = 0;
2978 // playlists, one per title
2979 // one playitem per media clip
2981 for( int ii=0; ii<idx.titles.size(); ++ii ) {
2983 media_info *ip = get(clip_id);
2984 program *pgm = ip->prog();
2985 mpls_pl *pp = new mpls_pl();
2986 pp->app_info.playback_type = BLURAY_PLAYBACK_TYPE_SEQUENTIAL;
2987 // pp->app_info.uo_mask.xxx = 1;
2988 int last = idx.titles[ii]->last;
2989 for( ; clip_id<=last; ++clip_id ) {
2992 mpls_pi *pi = new mpls_pi();
2993 pi->connection_condition = 1; // seamless
2994 // pi->uo_mask.xxx = 1;
2995 pi->in_time = pgm->start_time;
2996 pi->out_time = pgm->end_time;
2998 pi->still_mode = BLURAY_STILL_INFINITE;
2999 int64_t end_time = pgm->start_time + pgm->duration;
3000 if( pi->out_time < end_time ) pi->out_time = end_time;
3001 mpls_clip *cp = new mpls_clip();
3002 sprintf(cp->clip_id,"%05d", clip_id);
3003 pi->clip.append(cp);
3004 for( int kk=0; kk<ip->streams.size(); ++kk ) {
3005 stream *sp = ip->streams[kk];
3006 switch( sp->type ) {
3007 case AVMEDIA_TYPE_VIDEO: break;
3008 case AVMEDIA_TYPE_AUDIO: break;
3009 case AVMEDIA_TYPE_SUBTITLE: break;
3012 mpls_stream *ps = new mpls_stream();
3014 ps->stream_type = BLURAY_PG_TEXTST_STREAM;
3015 ps->coding_type = sp->coding_type;
3016 ps->format = sp->format;
3017 ps->rate = sp->rate;
3018 switch( sp->type ) {
3019 case AVMEDIA_TYPE_VIDEO:
3020 pi->stn.video.append(ps);
3022 case AVMEDIA_TYPE_AUDIO:
3023 memcpy(ps->lang, sp->lang, sizeof(ps->lang));
3024 pi->stn.audio.append(ps);
3026 case AVMEDIA_TYPE_SUBTITLE:
3027 memcpy(ps->lang, sp->lang, sizeof(ps->lang));
3028 pi->stn.pg.append(ps);
3034 pp->play_item.append(pi);
3036 // chapter marks every ch_duration seconds * 45Kticks, default 5 min
3037 int PCR_FREQ = 45000;
3038 if (ch_interval == 0)
3040 int64_t ch_duration = PCR_FREQ * ch_interval;
3041 int64_t mrktm = ch_duration;
3043 int pmark = 0, pitem = 0;
3044 mpls_pi *pi = pp->play_item[pitem];
3045 mpls_plm *pm = new mpls_plm();
3046 pm->mark_id = pmark++;
3047 pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
3048 pm->play_item_ref = pitem;
3049 pm->time = pi->in_time;
3050 pm->entry_es_pid = 0;
3051 pp->play_mark.append(pm);
3052 for( int jj=0; jj < pp->play_item.size(); ++jj ) {
3054 pi = pp->play_item[pitem];
3055 int64_t pi_duration = pi->out_time - pi->in_time;
3056 int64_t endtm = plytm + pi_duration;
3057 while( mrktm < endtm ) {
3058 pm = new mpls_plm();
3059 pm->mark_id = pmark++;
3060 pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
3061 pm->play_item_ref = pitem;
3062 pm->time = pi->in_time + mrktm - plytm;
3063 pm->entry_es_pid = 0;
3064 pp->play_mark.append(pm);
3065 mrktm += ch_duration;
3069 pm = new mpls_plm();
3070 pm->mark_id = pmark;
3071 pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
3072 pm->play_item_ref = pitem;
3073 pm->time = pi->out_time;
3074 pm->entry_es_pid = 0;
3075 pp->play_mark.append(pm);
3083 bd_path(const char *bp, const char *fmt, va_list ap)
3085 int n = sizeof(filename)-1;
3086 char *cp = filename;
3087 const char *pp = path;
3088 while( n>0 && (*cp=*pp)!=0 ) { --n; ++cp; ++pp; }
3089 while( n>0 && (*cp=*bp)!=0 ) { --n; ++cp; ++bp; }
3090 n -= vsnprintf(cp, n, fmt, ap);
3092 return n > 0 ? 0 : 1;
3096 bd_copy(const char *ifn, const char *fmt, ...)
3098 int bfrsz = 0x40000, ret = 1;
3100 FILE *ifp = fopen(ifn,"r");
3104 if( bd_path("/BDMV/", fmt, ap) ) return 1;
3106 FILE *ofp = fopen(filename,"w");
3108 setvbuf(ifp, 0, _IOFBF, 0x80000);
3109 setvbuf(ofp, 0, _IOFBF, 0x80000);
3112 while( !ret && n >= bfrsz ) {
3113 n = fread(bfr,1,bfrsz,ifp);
3114 if( n > 0 && (int)fwrite(bfr,1,n,ofp) != n ) {
3115 fprintf(stderr, "cant write: %s\n",filename);
3120 fprintf(stderr, "read error: %s = %m\n",ifn);
3124 fprintf(stderr, "write error: %s = %m\n",filename);
3128 fprintf(stderr, "close error: %s = %m\n",filename);
3135 fprintf(stderr, "cant copy clip %s\n",ifn);
3140 bd_open(const char *fmt, ...)
3143 if( !path ) return 0;
3146 if( bd_path("/BDMV/", fmt, ap) ) return 1;
3148 if( bs.open(filename) ) {
3149 fprintf(stderr, "cant open file %s\n",filename);
3156 bd_backup(const char *fmt, ...)
3159 if( !path ) return 0;
3162 FILE *ifp = fopen(filename,"r");
3166 if( bd_path("/BDMV/BACKUP/", fmt, ap) ) return 1;
3168 FILE *ofp = fopen(filename,"w");
3170 while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
3177 fprintf(stderr, "cant backup %s\n",filename);
3181 int Media::write(char *fn)
3185 if( bd_open("index.bdmv") ) return 1;
3186 if( idx.write() ) return 1;
3187 if( bd_backup("index.bdmv") ) return 1;
3189 if( bd_open("MovieObject.bdmv") ) return 1;
3190 if( mov.write() ) return 1;
3191 if( bd_backup("MovieObject.bdmv") ) return 1;
3193 for( int ii=0; ii<cl.size(); ++ii ) {
3194 if( bd_open("CLIPINF/%05d.clpi", ii) ) return 1;
3195 if( cl[ii]->write() ) return 1;
3196 if( bd_backup("CLIPINF/%05d.clpi", ii) ) return 1;
3199 for( int ii=0; ii<pl.size(); ++ii ) {
3200 if( bd_open("PLAYLIST/%05d.mpls", ii) ) return 1;
3201 if( pl[ii]->write() ) return 1;
3202 if( bd_backup("PLAYLIST/%05d.mpls", ii) ) return 1;
3208 main(int ac, char **av)
3212 av_log_set_level(AV_LOG_FATAL);
3213 //av_log_set_level(AV_LOG_VERBOSE);
3214 //av_log_set_level(AV_LOG_DEBUG);
3217 int start = 0, chapter_every_n_sec = 0;
3219 int opt = getopt(ac, av, "c:");
3221 chapter_every_n_sec = atoi(optarg); start = 4;
3222 path = av[3]; printf("Chapter interval: %i \n", chapter_every_n_sec );}
3225 if( mkbdmv(path) ) return 1;
3226 for( int ii=start; ii<ac; ++ii ) {
3228 // any dash seq followed by number sets curr title pgm_pid
3229 // single dash only sets title pgm_pid
3230 // double dash ends curr title, starts a new title
3231 // triple dash ends curr title as infinite still
3234 if( *++ap == '-' ) {
3236 if( *++ap == '-' ) { ++ap; mp->still = 1; }
3238 if( *ap >= '0' && *ap <= '9' )
3239 mp->pgm_pid = strtoul(ap,&ap,0);
3240 if( mp->brk ) mp = 0;
3242 fprintf(stderr, "err arg %d: %s\n",ii,av[ii]);
3247 mp = new media_info(av[ii]);
3250 fprintf(stderr, "cant scan media: %s\n", av[ii]);
3255 if( mp ) mp->brk = 1;
3257 if( media.compose(chapter_every_n_sec) ) {
3258 fprintf(stderr, "cant compose media\n");
3261 if( media.write(0) ) {
3262 fprintf(stderr, "cant prepare media\n");
3265 if( media.write(path) ) {
3266 fprintf(stderr, "cant write media\n");
3270 for( int ii=0; ii<media.size(); ++ii )
3271 if( media.bd_copy(media[ii]->filename, "STREAM/%05d.m2ts", ii) )