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:
Koroban 2013-07-23 18:43:40 +02:00
parent 503e803d47
commit 6d4f93e4ab
12 changed files with 78 additions and 94 deletions

67
README
View File

@ -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/

View File

@ -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!** **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) Detail informations on [doom9](http://forum.doom9.org/showthread.php?t=146493)

Binary file not shown.

View File

@ -155,6 +155,7 @@
#include "auto_split.h" #include "auto_split.h"
#include "palletize.h" #include "palletize.h"
#include "sup.h" #include "sup.h"
#include "ass.h"
#include "abstract_lists.h" #include "abstract_lists.h"
/* AVIS input code taken from muxers.c from the x264 project (GPLv2 or later). /* 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" " Might improve buffer problems, but is ugly.\n"
" [on=1, off=0]\n" " [on=1, off=0]\n"
" -b, --buffer-opt <integer> Optimize PG buffer size by image\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" "Example:\n"
" avs2bdnxml -t Undefined -l und -v 1080p -f 23.976 -a1 -p1 -b0 -m3 \\\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" " -u0 -e0 -n0 -z0 -o output.xml input.avs\n"
@ -714,12 +716,13 @@ typedef struct event_s
int start_frame; int start_frame;
int end_frame; int end_frame;
int graphics; int graphics;
int forced;
crop_t c[2]; crop_t c[2];
} event_t; } event_t;
STATIC_LIST(event, 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)); event_t *new = calloc(1, sizeof(event_t));
new->image_number = image; 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->graphics = graphics;
new->c[0] = crops[0]; new->c[0] = crops[0];
new->c[1] = crops[1]; new->c[1] = crops[1];
new->forced = forced;
event_list_insert_after(events, new); 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 image = start;
int d = end - start; int d = end - start;
if (!split_at) 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 else
{ {
while (d >= split_at + min_split) while (d >= split_at + min_split)
{ {
d -= split_at; 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; start += split_at;
} }
if (d) 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; int d = end - start;
if (!split_at) 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 else
{ {
while (d >= split_at + min_split) while (d >= split_at + min_split)
{ {
d -= split_at; 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; start += split_at;
} }
if (d) 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 *in_img = NULL, *old_img = NULL, *tmp = NULL, *out_buf = NULL;
char *intc_buf = NULL, *outtc_buf = NULL; char *intc_buf = NULL, *outtc_buf = NULL;
char *drop_frame = NULL; char *drop_frame = NULL;
char *mark_forced_string = "0";
char png_dir[MAX_PATH + 1] = {0}; char png_dir[MAX_PATH + 1] = {0};
crop_t crops[2]; crop_t crops[2];
pic_t pic; pic_t pic;
@ -853,6 +858,7 @@ int main (int argc, char *argv[])
int xml_output = 0; int xml_output = 0;
int allow_empty = 0; int allow_empty = 0;
int stricter = 0; int stricter = 0;
int mark_forced = 0;
sup_writer_t *sw = NULL; sup_writer_t *sw = NULL;
avis_input_t *avis_hnd; avis_input_t *avis_hnd;
stream_info_t *s_info = malloc(sizeof(stream_info_t)); 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'} , {"ugly", required_argument, 0, 'u'}
, {"null-xml", required_argument, 0, 'n'} , {"null-xml", required_argument, 0, 'n'}
, {"stricter", required_argument, 0, 'z'} , {"stricter", required_argument, 0, 'z'}
, {"forced", required_argument, 0, 'F'}
, {0, 0, 0, 0} , {0, 0, 0, 0}
}; };
int option_index = 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) if (c == -1)
break; break;
switch (c) switch (c)
@ -960,6 +967,9 @@ int main (int argc, char *argv[])
case 'z': case 'z':
stricter_string = optarg; stricter_string = optarg;
break; break;
case 'F':
mark_forced_string = optarg;
break;
default: default:
print_usage(); print_usage();
return 0; return 0;
@ -1028,6 +1038,7 @@ int main (int argc, char *argv[])
min_split = parse_int(minimum_split, "min-split", NULL); min_split = parse_int(minimum_split, "min-split", NULL);
if (!min_split) if (!min_split)
min_split = 1; min_split = 1;
mark_forced = parse_int(mark_forced_string, "forced", NULL);
/* TODO: Sanity check video_format and frame_rate. */ /* TODO: Sanity check video_format and frame_rate. */
@ -1160,13 +1171,13 @@ int main (int argc, char *argv[])
if (sup_output) if (sup_output)
{ {
assert(pal != NULL); 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) if (!xml_output)
free(pal); free(pal);
pal = NULL; pal = NULL;
} }
if (xml_output) 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; end_frame = i;
have_line = 0; have_line = 0;
} }
@ -1224,14 +1235,14 @@ int main (int argc, char *argv[])
if (sup_output) if (sup_output)
{ {
assert(pal != NULL); 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) if (!xml_output)
free(pal); free(pal);
pal = NULL; pal = NULL;
} }
if (xml_output) 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); free(pal);
pal = NULL; pal = NULL;
} }
@ -1304,7 +1315,7 @@ int main (int argc, char *argv[])
mk_timecode(event->end_frame + 1, fps, outtc_buf); 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++) 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); 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);

Binary file not shown.

Binary file not shown.

BIN
frame-a.o

Binary file not shown.

Binary file not shown.

BIN
sort.o

Binary file not shown.

17
sup.c
View File

@ -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); 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; sup_pcs_start_obj_t pcsso;
pcsso.picture = picture; pcsso.picture = picture;
pcsso.window = window; pcsso.window = window;
pcsso.forced = 0; pcsso.forced = (forced ? 64 : 0);
pcsso.x_off = x_off; pcsso.x_off = x_off;
pcsso.y_off = y_off; pcsso.y_off = y_off;
@ -513,7 +513,7 @@ void destroy_si (subtitle_info_t *si)
free(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 frame_ts, window_ts, decode_ts;
uint32_t window_ts_list[2], decode_ts_list[2]; 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 PCSS */
write_pcs_start(sw->fh, start_ts, dts, follower, num_crop, sw->im_w, sw->im_h, sw->fps_id, sw->comp_num); 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++) 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 */ /* Write WDS */
ts = start_ts - window_ts; /* Can be very slightly off, possible rounding error (FIXME: fixed?) */ 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; last_num_crop = si->num_crop;
memcpy(last_crops, si->crops, si->num_crop * sizeof(rect_t)); 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; new_composition = 0;
si_list_delete(sw->sil); si_list_delete(sw->sil);
destroy_si(si); destroy_si(si);
@ -735,7 +735,7 @@ void write_composition (sup_writer_t *sw)
sw->buffer = 0; 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)); subtitle_info_t *si = malloc(sizeof(subtitle_info_t));
int i; 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])); 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)); memcpy(si->pal, pal, 256 * sizeof(uint32_t));
si->forced = forced;
return si; return si;
} }
@ -774,7 +775,7 @@ void close_sup_writer (sup_writer_t *sw)
IMPLEMENT_LIST(si, subtitle_info_t) 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; rect_t tmp;
int buffer_increase; 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
View File

@ -31,6 +31,7 @@ typedef struct subtitle_info_s
int rle_len[2]; int rle_len[2];
uint8_t *rle[2]; uint8_t *rle[2];
uint32_t pal[256]; uint32_t pal[256];
int forced;
} subtitle_info_t; } subtitle_info_t;
DECLARE_LIST(si, 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); 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 */ /* 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 */ /* Call this once at the end */
void close_sup_writer (sup_writer_t *sw); void close_sup_writer (sup_writer_t *sw);

BIN
sup.o

Binary file not shown.