forked from theluyuan/avs2bdnxml
removed object files.
deleted old README. added parameter "-F" to mark all subtitles as forced. added usage to README file.
This commit is contained in:
parent
503e803d47
commit
6d4f93e4ab
67
README
67
README
@ -1,67 +0,0 @@
|
||||
AVS to BluRay SUP/PGS and BDN XML
|
||||
---------------------------------
|
||||
|
||||
This program can be used to transform AviSynth scripts, which produce RGBA
|
||||
output, to BDN XML+PNG format. This in turn can be transformed into a SUP file,
|
||||
which can be used to master a BluRay disc with subtitles.
|
||||
|
||||
Usage instructions:
|
||||
|
||||
0. If you want to build it:
|
||||
i586-mingw32msvc-gcc avs2bdnxml.c -o avs2bdnxml.exe -lpng -lz -lvfw32 \
|
||||
-Llib/ -O3 -Iinc/
|
||||
|
||||
1. Prepare subtitles. You can either produce subtitles in a normal format like
|
||||
SRT or ASS/SSA, or produce an RGBA video beforehand.
|
||||
|
||||
2. Create an AviSynth script. If you made a regular subtitle file, you can use
|
||||
something like this:
|
||||
|
||||
video=AviSource("video.avi")
|
||||
# This requires at least VSFilter 2.39
|
||||
MaskSub("subtitles.ext",video.width,video.height,
|
||||
video.framerate,video.framecount)
|
||||
|
||||
If you created an RGBA video, do something like this instead:
|
||||
|
||||
AviSource("subtitles_RGBA.avi")
|
||||
FlipVertical()
|
||||
|
||||
3. Run the program:
|
||||
avs2bdnxml input.avs Undefined und 1080p 23.976 output.xml
|
||||
|
||||
4. For some programs, you have to convert the PNG files to 8bit RGBA palette.
|
||||
This doesn't apply to BDSupEdit. You can do it with a tool like pngquant or
|
||||
pngnq.
|
||||
|
||||
pngquant: http://www.libpng.org/pub/png/apps/pngquant.html
|
||||
pngnq: http://pngnq.sourceforge.net/
|
||||
|
||||
5. You get a BDN XML file in the following format:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<BDN Version="0.93" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="BD-03-006-0093b BDN File Format.xsd">
|
||||
<Description>
|
||||
<Name Title="Undefined" Content=""/>
|
||||
<Language Code="und"/>
|
||||
<Format VideoFormat="[ 480i / 480p / 576i / 720p / 1080i /1080p ]" FrameRate="[ 23.976 / 24 / 25 / 29.97 / 50 / 59.94 ]" DropFrame="false"/>
|
||||
<Events LastEventOutTC="00:00:00:00" FirstEventInTC="00:00:00:00" ContentInTC="00:00:00:00"
|
||||
ContentOutTC="00:00:00:00" NumberofEvents="[ number of encoded frames ]" Type="Graphic"/>
|
||||
</Description>
|
||||
<Events>
|
||||
<Event Forced="[ False / True ]" InTC="00:00:00:00" OutTC="00:00:00:00">
|
||||
<Graphic Width="0" Height="0" X="0" Y="0">000000.png</Graphic>
|
||||
</Event>
|
||||
</Events>
|
||||
</BDN>
|
||||
|
||||
6. Use a program like BDSupEdit or BDSup2Sub to convert the BDN XML
|
||||
to a BD-SUP file. The rest is left as an exercise for the reader.
|
||||
|
||||
BDSupEdit: http://forum.doom9.org/showthread.php?t=146157
|
||||
BDSup2Sub: http://forum.doom9.org/showthread.php?t=145277
|
||||
|
||||
|
||||
|
||||
-- http://ps-auxw.de/avs2bdnxml/
|
38
README.md
38
README.md
@ -66,6 +66,44 @@ avs2bdnxml -t Undefined -l und -v 1080p -f 23.976 -a1 -p1 -b0 -m3 -u0 -e0 -n0 -z
|
||||
|
||||
**Don't use BDSupEdit or BDSup2Sub if you enabled -b for splitting images in multiple parts!**
|
||||
|
||||
Commandline Parameters
|
||||
----------------------
|
||||
|
||||
```
|
||||
Usage: avs2bdnxml [options] -o output input
|
||||
|
||||
Input has to be an AviSynth script with RGBA as output colorspace
|
||||
|
||||
-o, --output <string> Output file in BDN XML format
|
||||
For SUP/PGS output, use a .sup extension
|
||||
-j, --seek <integer> Start processing at this frame, first is 0
|
||||
-c, --count <integer> Number of input frames to process
|
||||
-t, --trackname <string> Name of track, like: Undefined
|
||||
-l, --language <string> Language code, like: und
|
||||
-v, --video-format <string> Either of: 480i, 480p, 576i,
|
||||
720p, 1080i, 1080p
|
||||
-f, --fps <float> Either of: 23.976, 24, 25, 29.97, 50, 59.94
|
||||
-x, --x-offset <integer> X offset, for use with partial frames.
|
||||
-y, --y-offset <integer> Y offset, for use with partial frames.
|
||||
-d, --t-offset <string> Offset timecodes by this many frames or
|
||||
given non-drop timecode (HH:MM:SS:FF).
|
||||
-s, --split-at <integer> Split events longer than this, in frames.
|
||||
Disabled when 0, which is the default.
|
||||
-m, --min-split <integer> Minimum length of line segment after split.
|
||||
-e, --even-y <integer> Enforce even Y coordinates. [on=1, off=0]
|
||||
-a, --autocrop <integer> Automatically crop output. [on=1, off=0]
|
||||
-p, --palette <integer> Output 8bit palette PNG. [on=1, off=0]
|
||||
-n, --null-xml <integer> Allow output of empty XML files. [on=1, off=0]
|
||||
-z, --stricter <integer> Stricter checks in the SUP writer. May lead to
|
||||
less optimized buffer use, but might raise
|
||||
compatibility. [on=1, off=0]
|
||||
-u, --ugly <integer> Allow splitting images in ugly ways.
|
||||
Might improve buffer problems, but is ugly.
|
||||
[on=1, off=0]
|
||||
-b, --buffer-opt <integer> Optimize PG buffer size by image
|
||||
splitting. [on=1, off=0]
|
||||
```
|
||||
|
||||
|
||||
Detail informations on [doom9](http://forum.doom9.org/showthread.php?t=146493)
|
||||
|
||||
|
BIN
auto_split.o
BIN
auto_split.o
Binary file not shown.
47
avs2bdnxml.c
47
avs2bdnxml.c
@ -155,6 +155,7 @@
|
||||
#include "auto_split.h"
|
||||
#include "palletize.h"
|
||||
#include "sup.h"
|
||||
#include "ass.h"
|
||||
#include "abstract_lists.h"
|
||||
|
||||
/* AVIS input code taken from muxers.c from the x264 project (GPLv2 or later).
|
||||
@ -632,7 +633,8 @@ void print_usage ()
|
||||
" Might improve buffer problems, but is ugly.\n"
|
||||
" [on=1, off=0]\n"
|
||||
" -b, --buffer-opt <integer> Optimize PG buffer size by image\n"
|
||||
" splitting. [on=1, off=0]\n\n"
|
||||
" splitting. [on=1, off=0]\n"
|
||||
" -F, --forced <integer> mark all subtitles as forced [on=1, off=0]\n\n"
|
||||
"Example:\n"
|
||||
" avs2bdnxml -t Undefined -l und -v 1080p -f 23.976 -a1 -p1 -b0 -m3 \\\n"
|
||||
" -u0 -e0 -n0 -z0 -o output.xml input.avs\n"
|
||||
@ -714,12 +716,13 @@ typedef struct event_s
|
||||
int start_frame;
|
||||
int end_frame;
|
||||
int graphics;
|
||||
int forced;
|
||||
crop_t c[2];
|
||||
} event_t;
|
||||
|
||||
STATIC_LIST(event, event_t)
|
||||
|
||||
void add_event_xml_real (event_list_t *events, int image, int start, int end, int graphics, crop_t *crops)
|
||||
void add_event_xml_real (event_list_t *events, int image, int start, int end, int graphics, crop_t *crops, int forced)
|
||||
{
|
||||
event_t *new = calloc(1, sizeof(event_t));
|
||||
new->image_number = image;
|
||||
@ -728,45 +731,46 @@ void add_event_xml_real (event_list_t *events, int image, int start, int end, in
|
||||
new->graphics = graphics;
|
||||
new->c[0] = crops[0];
|
||||
new->c[1] = crops[1];
|
||||
new->forced = forced;
|
||||
event_list_insert_after(events, new);
|
||||
}
|
||||
|
||||
void add_event_xml (event_list_t *events, int split_at, int min_split, int start, int end, int graphics, crop_t *crops)
|
||||
void add_event_xml (event_list_t *events, int split_at, int min_split, int start, int end, int graphics, crop_t *crops, int forced)
|
||||
{
|
||||
int image = start;
|
||||
int d = end - start;
|
||||
|
||||
if (!split_at)
|
||||
add_event_xml_real(events, image, start, end, graphics, crops);
|
||||
add_event_xml_real(events, image, start, end, graphics, crops, forced);
|
||||
else
|
||||
{
|
||||
while (d >= split_at + min_split)
|
||||
{
|
||||
d -= split_at;
|
||||
add_event_xml_real(events, image, start, start + split_at, graphics, crops);
|
||||
add_event_xml_real(events, image, start, start + split_at, graphics, crops, forced);
|
||||
start += split_at;
|
||||
}
|
||||
if (d)
|
||||
add_event_xml_real(events, image, start, start + d, graphics, crops);
|
||||
add_event_xml_real(events, image, start, start + d, graphics, crops, forced);
|
||||
}
|
||||
}
|
||||
|
||||
void write_sup_wrapper (sup_writer_t *sw, uint8_t *im, int num_crop, crop_t *crops, uint32_t *pal, int start, int end, int split_at, int min_split, int stricter)
|
||||
void write_sup_wrapper (sup_writer_t *sw, uint8_t *im, int num_crop, crop_t *crops, uint32_t *pal, int start, int end, int split_at, int min_split, int stricter, int forced)
|
||||
{
|
||||
int d = end - start;
|
||||
|
||||
if (!split_at)
|
||||
write_sup(sw, im, num_crop, crops, pal, start, end, stricter);
|
||||
write_sup(sw, im, num_crop, crops, pal, start, end, stricter, forced);
|
||||
else
|
||||
{
|
||||
while (d >= split_at + min_split)
|
||||
{
|
||||
d -= split_at;
|
||||
write_sup(sw, im, num_crop, crops, pal, start, start + split_at, stricter);
|
||||
write_sup(sw, im, num_crop, crops, pal, start, start + split_at, stricter, forced);
|
||||
start += split_at;
|
||||
}
|
||||
if (d)
|
||||
write_sup(sw, im, num_crop, crops, pal, start, start + d, stricter);
|
||||
write_sup(sw, im, num_crop, crops, pal, start, start + d, stricter, forced);
|
||||
}
|
||||
}
|
||||
|
||||
@ -820,6 +824,7 @@ int main (int argc, char *argv[])
|
||||
char *in_img = NULL, *old_img = NULL, *tmp = NULL, *out_buf = NULL;
|
||||
char *intc_buf = NULL, *outtc_buf = NULL;
|
||||
char *drop_frame = NULL;
|
||||
char *mark_forced_string = "0";
|
||||
char png_dir[MAX_PATH + 1] = {0};
|
||||
crop_t crops[2];
|
||||
pic_t pic;
|
||||
@ -853,6 +858,7 @@ int main (int argc, char *argv[])
|
||||
int xml_output = 0;
|
||||
int allow_empty = 0;
|
||||
int stricter = 0;
|
||||
int mark_forced = 0;
|
||||
sup_writer_t *sw = NULL;
|
||||
avis_input_t *avis_hnd;
|
||||
stream_info_t *s_info = malloc(sizeof(stream_info_t));
|
||||
@ -888,11 +894,12 @@ int main (int argc, char *argv[])
|
||||
, {"ugly", required_argument, 0, 'u'}
|
||||
, {"null-xml", required_argument, 0, 'n'}
|
||||
, {"stricter", required_argument, 0, 'z'}
|
||||
, {"forced", required_argument, 0, 'F'}
|
||||
, {0, 0, 0, 0}
|
||||
};
|
||||
int option_index = 0;
|
||||
|
||||
c = getopt_long(argc, argv, "o:j:c:t:l:v:f:x:y:d:b:s:m:e:p:a:u:n:z:", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "o:j:c:t:l:v:f:x:y:d:b:s:m:e:p:a:u:n:z:F:", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c)
|
||||
@ -960,6 +967,9 @@ int main (int argc, char *argv[])
|
||||
case 'z':
|
||||
stricter_string = optarg;
|
||||
break;
|
||||
case 'F':
|
||||
mark_forced_string = optarg;
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
return 0;
|
||||
@ -1028,6 +1038,7 @@ int main (int argc, char *argv[])
|
||||
min_split = parse_int(minimum_split, "min-split", NULL);
|
||||
if (!min_split)
|
||||
min_split = 1;
|
||||
mark_forced = parse_int(mark_forced_string, "forced", NULL);
|
||||
|
||||
/* TODO: Sanity check video_format and frame_rate. */
|
||||
|
||||
@ -1160,13 +1171,13 @@ int main (int argc, char *argv[])
|
||||
if (sup_output)
|
||||
{
|
||||
assert(pal != NULL);
|
||||
write_sup_wrapper(sw, (uint8_t *)out_buf, n_crop, crops, pal, start_frame + to, i + to, split_at, min_split, stricter);
|
||||
write_sup_wrapper(sw, (uint8_t *)out_buf, n_crop, crops, pal, start_frame + to, i + to, split_at, min_split, stricter, mark_forced);
|
||||
if (!xml_output)
|
||||
free(pal);
|
||||
pal = NULL;
|
||||
}
|
||||
if (xml_output)
|
||||
add_event_xml(events, split_at, min_split, start_frame + to, i + to, n_crop, crops);
|
||||
add_event_xml(events, split_at, min_split, start_frame + to, i + to, n_crop, crops, mark_forced);
|
||||
end_frame = i;
|
||||
have_line = 0;
|
||||
}
|
||||
@ -1224,14 +1235,14 @@ int main (int argc, char *argv[])
|
||||
if (sup_output)
|
||||
{
|
||||
assert(pal != NULL);
|
||||
write_sup_wrapper(sw, (uint8_t *)out_buf, n_crop, crops, pal, start_frame + to, i - 1 + to, split_at, min_split, stricter);
|
||||
write_sup_wrapper(sw, (uint8_t *)out_buf, n_crop, crops, pal, start_frame + to, i - 1 + to, split_at, min_split, stricter, mark_forced);
|
||||
if (!xml_output)
|
||||
free(pal);
|
||||
pal = NULL;
|
||||
}
|
||||
if (xml_output)
|
||||
{
|
||||
add_event_xml(events, split_at, min_split, start_frame + to, i - 1 + to, n_crop, crops);
|
||||
add_event_xml(events, split_at, min_split, start_frame + to, i - 1 + to, n_crop, crops, mark_forced);
|
||||
free(pal);
|
||||
pal = NULL;
|
||||
}
|
||||
@ -1298,13 +1309,13 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
mk_timecode(event->start_frame, fps, intc_buf);
|
||||
mk_timecode(event->end_frame, fps, outtc_buf);
|
||||
|
||||
|
||||
if (auto_cut && event->end_frame == frames - 1)
|
||||
{
|
||||
mk_timecode(event->end_frame + 1, fps, outtc_buf);
|
||||
}
|
||||
|
||||
fprintf(fh, "<Event Forced=\"False\" InTC=\"%s\" OutTC=\"%s\">\n", intc_buf, outtc_buf);
|
||||
|
||||
fprintf(fh, "<Event Forced=\"%s\" InTC=\"%s\" OutTC=\"%s\">\n", (event->forced ? "True" : "False"), intc_buf, outtc_buf);
|
||||
for (i = 0; i < event->graphics; i++)
|
||||
{
|
||||
fprintf(fh, "<Graphic Width=\"%d\" Height=\"%d\" X=\"%d\" Y=\"%d\">%08d_%d.png</Graphic>\n", event->c[i].w, event->c[i].h, xo + event->c[i].x, yo + event->c[i].y, event->image_number - to, i);
|
||||
|
BIN
avs2bdnxml.exe
BIN
avs2bdnxml.exe
Binary file not shown.
BIN
avs2bdnxml.o
BIN
avs2bdnxml.o
Binary file not shown.
BIN
palletize.o
BIN
palletize.o
Binary file not shown.
17
sup.c
17
sup.c
@ -194,13 +194,13 @@ static void write_pcs_start (FILE *fh, int start_time, int dts, int follower, in
|
||||
fwrite(&pcss, sizeof(pcss), 1, fh);
|
||||
}
|
||||
|
||||
static void write_pcs_start_obj (FILE *fh, int picture, int window, int x_off, int y_off)
|
||||
static void write_pcs_start_obj (FILE *fh, int picture, int window, int x_off, int y_off, int forced)
|
||||
{
|
||||
sup_pcs_start_obj_t pcsso;
|
||||
|
||||
pcsso.picture = picture;
|
||||
pcsso.window = window;
|
||||
pcsso.forced = 0;
|
||||
pcsso.forced = (forced ? 64 : 0);
|
||||
pcsso.x_off = x_off;
|
||||
pcsso.y_off = y_off;
|
||||
|
||||
@ -513,7 +513,7 @@ void destroy_si (subtitle_info_t *si)
|
||||
free(si);
|
||||
}
|
||||
|
||||
void write_subtitle (sup_writer_t *sw, uint8_t **rle, int *rle_len, int num_crop, rect_t *crops, uint32_t *pal, int start, int end, int new_composition)
|
||||
void write_subtitle (sup_writer_t *sw, uint8_t **rle, int *rle_len, int num_crop, rect_t *crops, uint32_t *pal, int start, int end, int new_composition, int forced)
|
||||
{
|
||||
uint32_t frame_ts, window_ts, decode_ts;
|
||||
uint32_t window_ts_list[2], decode_ts_list[2];
|
||||
@ -594,7 +594,7 @@ void write_subtitle (sup_writer_t *sw, uint8_t **rle, int *rle_len, int num_crop
|
||||
/* Write PCSS */
|
||||
write_pcs_start(sw->fh, start_ts, dts, follower, num_crop, sw->im_w, sw->im_h, sw->fps_id, sw->comp_num);
|
||||
for (i = 0; i < num_crop; i++)
|
||||
write_pcs_start_obj(sw->fh, sw->picture_offset + i, in_window[i], crops[i].x, crops[i].y);
|
||||
write_pcs_start_obj(sw->fh, sw->picture_offset + i, in_window[i], crops[i].x, crops[i].y, forced);
|
||||
|
||||
/* Write WDS */
|
||||
ts = start_ts - window_ts; /* Can be very slightly off, possible rounding error (FIXME: fixed?) */
|
||||
@ -701,7 +701,7 @@ void write_composition (sup_writer_t *sw)
|
||||
}
|
||||
last_num_crop = si->num_crop;
|
||||
memcpy(last_crops, si->crops, si->num_crop * sizeof(rect_t));
|
||||
write_subtitle(sw, si->rle, si->rle_len, si->num_crop, si->crops, si->pal, si->start, si->end, new_composition);
|
||||
write_subtitle(sw, si->rle, si->rle_len, si->num_crop, si->crops, si->pal, si->start, si->end, new_composition, si->forced);
|
||||
new_composition = 0;
|
||||
si_list_delete(sw->sil);
|
||||
destroy_si(si);
|
||||
@ -735,7 +735,7 @@ void write_composition (sup_writer_t *sw)
|
||||
sw->buffer = 0;
|
||||
}
|
||||
|
||||
subtitle_info_t *collect_si (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t *crops, uint32_t *pal, int start, int end)
|
||||
subtitle_info_t *collect_si (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t *crops, uint32_t *pal, int start, int end, int forced)
|
||||
{
|
||||
subtitle_info_t *si = malloc(sizeof(subtitle_info_t));
|
||||
int i;
|
||||
@ -752,6 +752,7 @@ subtitle_info_t *collect_si (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t
|
||||
si->rle[i] = rl_encode(im, sw->im_w, sw->im_h, si->crops[i], &(si->rle_len[i]));
|
||||
}
|
||||
memcpy(si->pal, pal, 256 * sizeof(uint32_t));
|
||||
si->forced = forced;
|
||||
|
||||
return si;
|
||||
}
|
||||
@ -774,7 +775,7 @@ void close_sup_writer (sup_writer_t *sw)
|
||||
|
||||
IMPLEMENT_LIST(si, subtitle_info_t)
|
||||
|
||||
void write_sup (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t *crops, uint32_t *pal, int start, int end, int strict)
|
||||
void write_sup (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t *crops, uint32_t *pal, int start, int end, int strict, int forced)
|
||||
{
|
||||
rect_t tmp;
|
||||
int buffer_increase;
|
||||
@ -831,6 +832,6 @@ void write_sup (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t *crops, uint
|
||||
}
|
||||
}
|
||||
|
||||
si_list_insert_after(sw->sil, collect_si(sw, im, num_crop, crops, pal, start, end));
|
||||
si_list_insert_after(sw->sil, collect_si(sw, im, num_crop, crops, pal, start, end, forced));
|
||||
}
|
||||
|
||||
|
3
sup.h
3
sup.h
@ -31,6 +31,7 @@ typedef struct subtitle_info_s
|
||||
int rle_len[2];
|
||||
uint8_t *rle[2];
|
||||
uint32_t pal[256];
|
||||
int forced;
|
||||
} subtitle_info_t;
|
||||
|
||||
DECLARE_LIST(si, subtitle_info_t)
|
||||
@ -64,7 +65,7 @@ typedef struct sup_writer_s
|
||||
sup_writer_t *new_sup_writer (char *filename, int im_w, int im_h, int fps_num, int fps_den);
|
||||
|
||||
/* Write sup data for subtitle */
|
||||
void write_sup (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t *crops, uint32_t *pal, int start, int end, int strict);
|
||||
void write_sup (sup_writer_t *sw, uint8_t *im, int num_crop, rect_t *crops, uint32_t *pal, int start, int end, int strict, int forced);
|
||||
|
||||
/* Call this once at the end */
|
||||
void close_sup_writer (sup_writer_t *sw);
|
||||
|
Loading…
Reference in New Issue
Block a user