本帖最后由 shane007 于 2021-1-2 13:56 编辑
9 x4 Y* I0 d. t0 R/ v- c* o) i$ {, y Y$ N. H: u
最近找到了一些和幽魂系列Phantasmagoria 有关的资料,6 d1 p# W3 p) h P4 ]2 l8 r
也许将来可以用于汉化。
( K) Q V/ i# {! z+ s4 L( |6 t( U' E& ]* N
和日文版有关的信息6 N- Y+ k/ x" }* ^
http://anthonylarme.tripod.com/phantas/phintgtp.html1 x5 }( u8 s3 b# i2 x# C
1 q. ?" x# `4 w7 K. O
相关工具' O4 ]. V& D' u
http://anthonylarme.tripod.com/phantas/phcheats.html1 O( Q. L. _: g' t& ?
-----------------------------------------------------------------------! Q$ o3 d4 C6 r
2012/1/2 更新
' X3 ~8 a& Z8 x1 O! A关于幽魂游戏的字幕( A' }+ z: l2 E+ {) g. y
Phantasmagoria subtitles function discovered - ScummVM :: Forums
: ^; b y) w5 F) {8 ~! Z' f7 K/ `8 m/ D0 Y1 I) ~( x
VMD文件# w: v! x1 w2 F' B) h3 P0 N7 @0 c
Subtitling Sierra VMD Files | Breaking Eggs And Making Omelettes (multimedia.cx)VMD - MultimediaWiki
4 s1 @1 F- ~- D5 P* U0 \* W1 `# Y/ I
字幕
" X2 C0 V) B% eSubtitling Sierra RBT Files | Breaking Eggs And Making Omelettes (multimedia.cx)
' S- [/ T& C9 ?+ l
+ s1 X8 k' l- e; V9 `) X2 a: y. TFFmpeg/subtitle-rbt.c at feature/VMD_encoder · multimediamike/FFmpeg · GitHub
2 r7 R$ }0 }3 q$ L( M! ?* W, x; z0 I- /*6 I% o2 P' x/ n! s, @& _2 u r
- * subtitle-rbt.c/ A6 ~1 w: C! p
- * by Mike Melanson (mike -at- multimedia.cx). z2 ]) Q* {( p
- *
, U9 o( H/ a% w+ @: G5 y - * build with this command:6 d3 p6 |6 M: R( p( c5 N
- * gcc -g -Wall subtitle-rbt.c -o subtitle-rbt -lm -lass
f; P, G( P, ]7 P3 e - */, M* p0 ?- t* i. D6 A* N8 M. ~
- N& x! c4 t4 k t t n
- #include <inttypes.h>9 c2 ]8 q( g) w5 l/ M
- #include <math.h>+ z, f, f5 B2 L$ Z& I# i6 D6 C
- #include <stdio.h>
/ g ^: g& o8 f. ?9 a9 d0 A) u - #include <stdlib.h>
+ U; c0 W* o+ l+ r" K - #include <string.h>0 u% \" r; c8 w1 {- ?5 J! d3 y" P
( [* N: I! q2 ^1 M+ i- #include <ass/ass.h>
, o( g. E; R4 B- H }
5 C, Z/ ], m: L. I: j5 l/ n- #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])$ N0 T/ y1 Y! z& i/ f+ {% W
- 0 T9 c. B( T% d, `. m; N
- #define LE_32(x) (((uint32_t)(((uint8_t*)(x))[3]) << 24) | \
: f- S. m& `: H$ I4 n- s9 i, A- P9 K - (((uint8_t*)(x))[2] << 16) | \
3 m& N8 R$ s1 X/ L8 K) x - (((uint8_t*)(x))[1] << 8) | \
: [ R4 ?8 S' a! O - ((uint8_t*)(x))[0])
. K+ i6 Q+ s. f3 o
9 ^' M# E; ~, Z: t7 R' U. q O) p7 v- /*********************************************************************/; u' |1 _/ v+ M9 D5 k
- P4 D- |5 _2 e
- /* Bit reader stuff */1 A" a4 J2 \2 q5 A4 q* u% z
% k* U/ M) y% b- typedef struct
# I6 T; A6 n" F4 ~ - {
0 ?7 w& b. O& B$ t! M0 Y6 g - uint8_t *bytestream;" Y" P2 M j d
- int bytestream_size;1 E' ~1 V) P6 @% w7 T8 c+ {, e
- int index;& |# V: B( T' T, j
- uint32_t bits;: a$ t% u" E: ], m
- int bits_in_buffer;4 g: z" D4 ]1 N. \( p# o
- } get_bits_context;
0 ~; X, v+ l A% q* p; H - " W$ v+ x8 z2 ^: g
- static inline void reload_bits(get_bits_context *gb)
& k0 l# R! l h$ k" r [ - {7 `3 u7 j& g% E/ {4 G+ R3 t2 ^
- while (gb->bits_in_buffer <= 24)
A0 X7 r ~ C9 i' ~( E - {
9 D8 M5 @/ @# }( w - if (gb->index < gb->bytestream_size)' x" W1 L3 W! E! A! \$ L
- gb->bits |= (gb->bytestream[gb->index++] << (24 - gb->bits_in_buffer));
. B( C- Z' I! ^: ? - gb->bits_in_buffer += 8;
4 B3 N* K9 H; U. B# [) d z$ k - }$ V+ ]- ]. `( _/ S
- }
5 i+ @! l: `& G$ k
5 ]. G6 w( S2 Z0 Z1 X- static void init_get_bits(get_bits_context *gb, uint8_t *bytestream, int size)
$ x n# l6 b' u( W! f - {( B# m5 }& j- B/ F
- gb->bytestream = malloc(size);# N- d _& n m% d8 ~: d4 P
- memcpy(gb->bytestream, bytestream, size);
- I, v$ ?9 Z- ` - gb->bytestream_size = size;
% c) z1 h1 Q- r, A - gb->index = 0;
$ Q1 U! _% n: Z5 E2 c - gb->bits = 0;
4 X$ s$ P! j0 e8 b% |- j5 n - gb->bits_in_buffer = 0;7 o- r# N- i# S/ i5 @% o ?
- 7 T1 q7 {7 ^( s' V* `# F
- reload_bits(gb);5 N) Q; a" V- r9 u9 F' Q4 R3 _- k) j
- }
7 k0 b3 z8 f$ m0 M9 l, R
( Q* L+ z8 M% x. Z2 |; G- /* read bits without consuming them from the stream */! Y. g( L. R- Z& i
- static int view_bits(get_bits_context *gb, int count)' z/ X. E; u) Y: M7 w. V
- {
: T0 G! s, v' J7 W: M - if (count >= 24), t: {" [# J- Y- Q
- return -1;
9 m* ^- ^1 `+ C" d: `) G( n8 F - if (gb->bits_in_buffer < count)
7 z+ G- _& _% r6 m5 B) y6 U. s - reload_bits(gb);
& L5 |& _$ c, L; C5 D/ X - return (gb->bits >> (32 - count));
6 c* i; Y ]' x: z$ [6 o2 m - }; d5 L5 e& A \0 S8 y7 E& G8 V
- ( B3 d' Z, n* {7 f& J$ [% ~
- /* read and consume bits from the stream */
( J1 z8 P7 W9 E3 B3 A! I& }5 T - static int read_bits(get_bits_context *gb, int count)
* j6 X; B/ G- ?: x$ o! v - {( R1 f; f: @: }9 Q3 A9 S9 T3 G. E+ p
- int value;
R% r3 [; ]* x- v; ]3 P
* d3 K, z0 y+ C6 {5 m# N- if (count >= 24)
% R9 @, `" H2 Q& h4 _ - return -1;) B4 R5 N. Y$ u1 N! f2 D( ?' w
- 0 T. P3 p8 Z5 w+ F' X! S2 ^
- value = view_bits(gb, count);
& T: O. P& U, z; i8 p% i0 a, E - gb->bits <<= count;
Q8 x, ?% q" j( E* H1 b - gb->bits_in_buffer -= count;0 p& O: _6 {/ U8 d' _
- r B9 V6 ~+ _/ _3 z! E
- return value;
! H6 F; R' i+ h) f: h6 B3 w7 O! W! i - }; [' a' M8 v2 T9 Z
0 L9 b B7 o; ?0 q; M- static void delete_get_bits(get_bits_context *gb)
% z6 _3 a4 k6 X# @9 { - {
G9 Q2 D" n! A" Y; H, b! { - free(gb->bytestream);
& A& t) ?+ ?4 j/ T2 L* v+ `3 a" E; n - }/ b5 d: h6 [3 H- J
. N5 i ]2 Y! ~- _) ^2 H% O9 ~- /*********************************************************************/" z! o" u; K. i. v' P$ C
- ; b0 C1 `' k! J) g& b' p2 i
- /* Bit writer stuff */
/ J* V; O- M0 C) r6 P2 H
" x" _$ B7 |0 k- #define MAX_PUT_BITS_BYTES 63000, p3 I' |1 t& v3 H/ H' h' j
- typedef struct
9 e1 L" n' h/ z4 c; V - {$ i3 u, b* s& ]
- uint8_t bytes[MAX_PUT_BITS_BYTES];
, o- h; ~: f+ o - int byte_index;
$ s' j1 a$ y! ^; V6 ? - uint32_t bit_buffer;. J" a5 b- r; @: L) } }3 w
- int bits_buffered;
0 c' @$ T! X" ?+ h - } put_bits_context;
1 l Q7 j7 t1 B/ Y1 ^% w' k4 e
# ?- u0 I; s3 w$ M- static void reset_put_bits(put_bits_context *pb)
4 U. \4 J1 _2 ~0 X O; ? - {
( a- Y* I6 r3 |. w7 \9 V - memset(pb->bytes, 0, MAX_PUT_BITS_BYTES);
$ j9 c, U9 p7 `% }$ x" K$ f - pb->byte_index = 0;
% D& x, t8 ~5 |% f: C) m* q - pb->bit_buffer = 0;
4 T% n$ C v4 w k, I - pb->bits_buffered = 0;
( @3 v6 [3 A5 H6 q. i - }8 K" L( {: x( S3 e3 o. A' H
/ C# ]: m3 E6 n3 k- L- static put_bits_context *init_put_bits()
4 |5 K f n: x) n0 U: Y+ F; k - {
7 I7 M n& ^* S8 D4 w4 {8 o - put_bits_context *pb;
3 U. s ~! d1 H& T O6 m! m
( T3 s% a8 m2 s# o0 f6 m- pb = malloc(sizeof(put_bits_context));/ Z/ s& h2 q4 Z4 T
- reset_put_bits(pb);( f# \, p& z" J3 j) d
- $ C$ l$ y3 V4 k) P @& o% R( w8 Z- a
- return pb;
6 U$ X9 G6 L5 i& Z: \ - }: u$ J3 d- Q3 E9 Y) S) r
6 |4 l7 i3 H1 h* V2 L% t- static void put_bits(put_bits_context *pb, int bits, int count), a' [ m, e% T' m& O# A! @
- {5 K2 U5 M+ k& V8 D
- pb->bit_buffer <<= count;& Q+ m" Y3 \3 a6 J+ \' V
- pb->bit_buffer |= (bits & (~(0xFFFFFFFF << count)));
5 [1 Y$ H. \ m9 L - pb->bits_buffered += count;
5 V/ T* _8 z+ }. r& L6 B - s$ S# R% Q% U# N+ g
- while (pb->bits_buffered >= 8)4 a' f" S. O/ ^0 y5 \5 L6 b( F
- {0 f5 I* V2 Y7 }$ G
- pb->bytes[pb->byte_index++] = pb->bit_buffer >> (pb->bits_buffered - 8);, \& C- Y d+ B; X9 \
- pb->bit_buffer &= (~(0xFFFFFFFF << (pb->bits_buffered - 8)));: ` S7 w2 c/ v, z* I- ~* e9 y: ?
- pb->bits_buffered -= 8;. j" }: V7 X# i% S1 N
- }: c5 B* {0 d M- k0 E5 j8 F8 ^+ ?
% ] g ^3 q! h0 h6 F- if (pb->byte_index >= MAX_PUT_BITS_BYTES)
! }# h9 T/ H3 U- [, Q - {
, c; v* J1 s- d1 E - printf("HELP! Bit overflow\n");
, j8 M1 R7 H u o0 T! W9 S - exit(1);
1 c+ k% T, X. X9 h( ~ - }& S& [7 D3 N8 b% r5 A& Y; _
- }
0 e' M$ d+ f- \5 `8 s - " S: R2 o9 d1 L7 d9 {
- static void put_bits_flush(put_bits_context *pb)% v6 B( K, ?( h
- {7 m" u- `% L. j1 L$ f$ t
- if (pb->bits_buffered > 0)3 [. i U6 ^( U
- pb->bytes[pb->byte_index++] = pb->bit_buffer << (8 - pb->bits_buffered);- e5 _: Z6 i. V2 z
- }/ @0 F8 W* Q" U d3 w1 ^
/ _/ ]+ k! ?! ]# ?1 \* c1 g6 z- static void delete_put_bits(put_bits_context *pb)& a( f: k/ l6 C/ b1 z
- {# k6 ]+ Q0 O/ i* E2 k
- free(pb->bytes);
% G: x n- Q- x2 b( X - }
! u6 P2 C$ w6 H
4 F& L# N) K( F: v) G! ?- /*********************************************************************/
. g& w# }1 n2 x r! M( }6 D
+ k0 {$ C; l" e' S- /* RBT functions */' u( N# Q' A" w2 X5 G: y: D8 d
+ }) F1 ?' V3 b) z% ]- #define PALETTE_COUNT 256/ ^6 J& n8 F2 G
- #define RBT_HEADER_SIZE 60: x3 ^7 O% m* l
- #define UNKNOWN_TABLE_SIZE (1024+512)
8 A2 a2 {( {, u, y8 E: A - #define SUBTITLE_THRESHOLD 0x70" C- P2 R8 k' W* }; }! ?5 U
- #define MILLISECONDS_PER_FRAME 100
+ @! C9 l* O( N5 P/ h) o0 ^: f# `
# o3 W+ g! ?6 e. |% `4 z- /* VLC table */
/ p' M0 v" a! y4 o9 P& V% t - #define VLC_SIZE 4
: P* a9 c. p9 I( e! p - static struct2 q1 t0 N4 ^3 n
- {0 k/ {4 I/ l' B- ~. F- n
- int count;' C, U' V+ t a
- int value;
6 ^2 Q# G! e3 z - } lzs_vlc_table[] =
' D4 ]: q9 j: H( j: v9 y. s - {1 ^; P$ A6 @6 G7 X% n7 C6 `8 ~
- /* code length = 2 bits; value = 2 */
( `# E( Y2 S: P3 @# b; b, p+ i/ h - /* 0000 */ { 2, 2 },) J% l4 c+ _) [1 ?
- /* 0001 */ { 2, 2 },
* p" L, ^4 v& ~0 O. I - /* 0010 */ { 2, 2 },: c0 Q- C& [9 S7 v
- /* 0011 */ { 2, 2 },# K: f" B5 ]( H4 ? h; A) e
- 8 L( f0 N8 L0 A$ X
- /* code length = 2 bits; value = 3 */
7 a! N% f# M' M* g/ _# ?+ W - /* 0100 */ { 2, 3 },% h+ \0 v7 I) A; W
- /* 0101 */ { 2, 3 },( d% C8 g* N; Q; D" H, Q
- /* 0110 */ { 2, 3 },
1 y% ]* B w f4 ] - /* 0111 */ { 2, 3 },
8 F* w3 O3 v$ @4 b - ( k' g+ w: m' U* G/ Y
- /* code length = 2 bits; value = 4 */
! H5 h2 C/ Z- h1 P - /* 1000 */ { 2, 4 },3 n S% M: q% ?' T
- /* 1001 */ { 2, 4 },! |8 j* M% D, J8 ^, d
- /* 1010 */ { 2, 4 },' ~* q& J. t5 d& R5 ~
- /* 1011 */ { 2, 4 },4 X- M0 S0 y5 E$ t7 y6 H
- ) E/ j5 u' L, m, T) }
- /* code length = 4 bits; value = 5 */" I9 }9 k* F4 i
- /* 1100 */ { 4, 5 },* w5 m" X; w* h+ {7 R2 y+ I7 ~
/ m6 S/ ^$ A- v9 X6 H- /* code length = 4 bits; value = 6 */! J" v: o* ~2 K+ C8 V
- /* 1101 */ { 4, 6 },6 |- _2 C; U' b( j- C1 X) V6 c
& I0 K B1 f( k; _; Y- /* code length = 4 bits; value = 7 */
4 Q" y8 s& Z% d- m0 n9 @! z - /* 1110 */ { 4, 7 },8 K+ B4 }( A; M9 r. j
% ~! u U, T" U5 {$ [- /* special case */
$ Z: Y+ S+ a6 {3 M, m# @ - /* 1111 */ { 4, 8 }: V8 O5 i3 w+ l) }
- };% s2 R7 E* j8 U3 T) | s1 O
- L! n7 X7 N6 ]. k4 `7 r: }$ n
- typedef struct6 A7 w1 R0 ?" a9 z, V' c
- {
1 R; k& D7 o4 s8 T1 V, I3 R - int version;0 a6 N7 W3 m# S7 C; C4 F+ M% @8 k8 }7 b$ Q
- int width;4 }" Q$ ]& Q9 \: D/ {; |! X* z
- int height;
) M, J% ?$ X: P- _ - int frame_count;
2 ?3 S2 o* w# b - int audio_chunk_size;, n5 z% s/ c% L- S) s: }% O
- uint8_t palette[PALETTE_COUNT * 3];8 c$ m) x3 v8 a% K3 f6 o
- off_t video_frame_size_table_offset;5 B2 M; }7 X2 v
- uint8_t *video_frame_size_table;7 G/ ?6 Y" ?. k2 L" W
- off_t frame_size_table_offset;
0 {, F: ?* V! [5 \ g' t - uint8_t *frame_size_table;
5 o z* Q4 o( B) n3 l - uint8_t *frame_load_buffer;
3 [$ m* O- f5 i% U7 l- O2 i- D - int dump_frames;
7 ?. |7 V- M( ?% c/ O0 r$ ]7 L - / r5 J$ l8 A1 @0 v5 Y
- /* subtitle library */
A& w: u) g" Y - ASS_Library *ass_lib;) G. k6 ^& u5 z$ d
- ASS_Renderer *ass_renderer;
; {$ i# J$ b0 Y$ q) S/ E6 j$ f - ASS_Track *ass_track;
2 k& I9 m: ?3 ^" k4 f+ _" u- i1 c2 W - } rbt_dec_context;' D! c( Z' F% y
- % O B) C! K" o0 ]5 { f$ K* F
- static void dump_pnm_file(char *filename, rbt_dec_context *rbt,
) X' x! z0 R% ~4 v2 W$ i" l, o - uint8_t *image, int width, int height)* J. M+ ^' {$ i0 F5 ^' e
- {* y/ q1 H2 @; j" M9 w; f9 O
- FILE *outfile;( L( |7 |3 {0 C B( V" D0 [" N1 N
- uint8_t bytes[3];+ S4 B2 A. q1 x$ [7 t8 o
- int p;
% I/ i: P ~! h0 l. Z2 Q4 A+ t - uint8_t pixel;
) F4 d. }( K/ a% `+ B1 z1 F8 v2 [
% ^9 U# M6 e4 P4 }0 M, J! h- outfile = fopen(filename, "wb");& U, {! }* c' t6 B! F, H1 U3 X5 R& I
- fprintf(outfile, "P6\n%d %d\n255\n", width, height);
j4 F# [( G! ]3 v' K* z/ r9 O, h9 I - for (p = 0; p < width * height; p++): n3 J+ D- [8 i _% Y
- {
" Z6 g% ]% \: t) n, \+ v1 n - pixel = image[p];
+ ^. Q0 R- Y" x5 l1 f; d) x - bytes[0] = rbt->palette[pixel*3+0];+ G3 h2 R8 K0 O% p8 Y) I8 m- k$ C
- bytes[1] = rbt->palette[pixel*3+1];
, ]" i, ?9 X9 V - bytes[2] = rbt->palette[pixel*3+2];8 ?3 v: w* L e8 _$ B1 \
- fwrite(bytes, 3, 1, outfile);
& N' [% k: q$ M1 S7 B - }
/ t7 ]9 t* ?& c - fclose(outfile);5 {5 Z% g) R* c( m H* d3 l! o
- }
8 y- `; a7 E7 n0 \; Q - # P. H. d5 l( g, k3 E; r3 c7 I
- static int load_and_copy_rbt_header(rbt_dec_context *rbt, FILE *inrbt_file, FILE *outrbt_file)0 M+ C5 w9 o! o2 \# b' ]* t
- {
) X8 o, x3 k$ c$ k; h$ m - uint8_t header[RBT_HEADER_SIZE];
+ V% R i7 `- _! _% c8 ^- | - int palette_data_size;7 m: h% O/ f; }* H+ O5 N% j! m* \
- uint8_t *palette_chunk;
$ h* K7 I8 X, @; z( q0 y% n/ s7 | - int unknown_chunk_size;2 c5 b3 {$ f% d
- uint8_t *unknown_chunk;
: x5 F& y! y& W0 y, e' y# A4 F, u9 j - uint8_t unknown_table[UNKNOWN_TABLE_SIZE];
! O4 z! N8 S6 ~- A; S - off_t padding_size;
# N" w0 C, @ V' {+ w - uint8_t *padding;
, G, |# o8 _) U7 P8 G - int i;; u3 Y& h* t+ y1 A6 O% e
- int frame_size; b) n) K/ ~$ o2 @
- int max_frame_size;
+ Q! ?: B! ]& u( d8 B, {6 @ - int first_palette_index;
( s# e5 M8 L! v% N6 q' n& `3 O - int palette_count;. K3 W; d% k( \5 T2 q. h; L
- int palette_type;
! N2 @2 M% v, K% s. C% t) O - int palette_index;
9 c% Q9 k' K0 m" v
# G5 m/ j. s$ g* y X$ e1 }- fseek(inrbt_file, 0, SEEK_SET);" H2 p! ~8 A3 E1 z$ m, f: Y, V
- fseek(outrbt_file, 0, SEEK_SET);6 P% y, f/ T1 C/ X/ k$ N
- ' ^* B% A% n$ Y( Y: u; S
- /* load the header */7 E/ @, t; }7 Z$ L. N2 F
- if (fread(header, RBT_HEADER_SIZE, 1, inrbt_file) != 1): x: p5 G* Z1 l+ F" R
- {
8 [; C! {; X# h; n - printf("problem reading initial RBT header\n");% l7 h* v7 k0 P0 g
- return 0;7 d1 r" E9 K0 N; ^/ F( u
- }9 M: h1 z8 I# D2 @8 G: }
9 M8 y" k/ p* `. j; l9 f, _- /* copy header to the output */
. N& l2 {0 J5 a& g( p - if (fwrite(header, RBT_HEADER_SIZE, 1, outrbt_file) != 1)
+ w! J: F" I6 _ - {
1 w9 L# j6 _( I5 |; {; M5 n! J/ r - printf("problem writing initial RBT header\n");7 [8 y+ ] i$ v# M$ U1 o$ s
- return 0;" n0 O2 W7 C* s; _5 e/ T% ^+ j
- }( \# X% D. O1 R0 i4 S$ A8 i- o
; Y$ _1 n. n: H; a; }% |: Z4 j- rbt->version = LE_16(&header[6]);
4 t4 ?2 I5 a. V: e' Z - rbt->audio_chunk_size = LE_16(&header[8]);
+ n4 T1 v3 n3 h! Q9 ? - rbt->frame_count = LE_16(&header[14]);7 B, w9 N+ o+ r
. ~# R1 [& R4 j1 A/ p# Z* {- /* transfer the unknown data, if it's there */
- w# S2 u( [4 p7 a - unknown_chunk_size = LE_16(&header[18]);
( i {$ |& m6 O/ U' R" M - if (unknown_chunk_size > 0)6 g; p4 `' f3 @
- {
4 j p* A/ H5 W: W1 x7 b - unknown_chunk = malloc(unknown_chunk_size);+ S- E- U5 w, O- Z# H6 Z2 G A
- if (fread(unknown_chunk, unknown_chunk_size, 1, inrbt_file) != 1)/ h- G6 [7 Z4 M: [% n7 L6 m
- {& L- }7 Q' |* c- @+ }
- printf("problem reading unknown data\n");
! C! q/ g2 Q$ Q - return 0;/ U+ k- W( O/ a) {" z- j, ^
- }
2 m8 g- L) b' H) d - if (fwrite(unknown_chunk, unknown_chunk_size, 1, outrbt_file) != 1)
! w# V/ p( Z0 b3 ` - {: L% z8 B1 C1 b# G, C# e
- printf("problem writing unknown data\n");
8 \2 d9 x1 R$ ? - return 0;
7 n2 B. o6 J! A! |3 e' @% V' \ - }
* _* _1 ~/ I f: v$ {+ b - free(unknown_chunk);7 ^! ]! D* x! n
- }, E, b: F: S+ F" M
- 8 C% q9 V* W. H4 L1 X0 b
- /* transfer the palette chunk */
, {. r+ [/ B7 E7 _: R6 h& ?0 j - palette_data_size = LE_16(&header[16]);
9 @1 R4 v& \# [3 y9 M1 X/ S - palette_chunk = malloc(palette_data_size);. `3 E- r8 d7 q
- if (fread(palette_chunk, palette_data_size, 1, inrbt_file) != 1)
) F: Z5 p- e! V; G; N! H3 ` r - {
! l4 k) U5 n' h5 V - printf("problem reading palette\n");1 k$ C; J) `; g# Z
- return 0;
4 Y( W6 @6 X* I1 ?! v - }( O' M6 M7 f0 E5 ^/ @
- if (fwrite(palette_chunk, palette_data_size, 1, outrbt_file) != 1)# J- j" Y1 N* `0 I2 V& ]
- {, a) z1 _( @* ]( i+ u9 _; |
- printf("problem writing palette\n");" |/ o+ \! b; H5 }
- return 0;
! ?& {2 ~$ H) K$ a5 ` - }
8 d1 L4 r$ }( T- n - /* load the palette into the internal context */0 }# t& O' y6 l/ ~1 D
- memset(rbt->palette, 0, PALETTE_COUNT * 3);
+ s5 s( C, d% @+ [ v! I - first_palette_index = palette_chunk[25];9 K1 F4 b' o- J0 s
- palette_count = LE_16(&palette_chunk[29]);
U6 p% Q1 f% q1 [: n; I - palette_type = palette_chunk[32];
. ?2 [7 V4 S0 n3 U9 { - palette_index = (palette_type == 0) ? 38 : 37;# m8 l: h" L2 M' W
- for (i = first_palette_index; i < first_palette_index + palette_count; i++)
" R- Y: R1 F9 {5 B8 s: D6 ` - {
- O4 h$ b6 b) S( |, W; V$ u4 j6 ~ - rbt->palette[i*3+0] = palette_chunk[palette_index++];
- O/ l7 [& `9 y: h% U) Q! N - rbt->palette[i*3+1] = palette_chunk[palette_index++];9 h# u1 @& D( `% U7 j% G6 A( M
- rbt->palette[i*3+2] = palette_chunk[palette_index++];( W/ |# [+ K% B5 J
- }
" s+ S% E2 ^5 r1 c; x; K - free(palette_chunk);
$ b0 o+ i$ H- L - ]6 {7 |$ _6 h5 \" c- k2 E7 E
- /* copy the video frame size table (2 bytes per frame), as a placeholder */1 A% f, I& T7 u$ X) u2 v# _
- rbt->video_frame_size_table = malloc(rbt->frame_count * sizeof(uint16_t));
$ X& N& ?4 w. L @( ~ - if (fread(rbt->video_frame_size_table, rbt->frame_count * sizeof(uint16_t), 1, inrbt_file) != 1)
( h1 W9 Q7 }% b1 j: U4 D - {
8 H0 S! M0 X6 r9 m - printf("problem reading frame table\n");0 g" z& z2 k. m& e' P" O
- return 0;
Z# U% a) Y5 e6 H6 `/ c - }* |, r3 \4 A/ a: Y8 a& _$ A5 Y. L
- rbt->video_frame_size_table_offset = ftell(outrbt_file);
, e( S: H: u3 A6 x/ Y% O - if (fwrite(rbt->video_frame_size_table, rbt->frame_count * sizeof(uint16_t), 1, outrbt_file) != 1)- R( E& b# \. l' ]6 ]
- {$ I" T/ T7 j7 Q* |& l0 p
- printf("problem writing frame table\n");5 \: y, P' i* M/ L
- return 0;: X- w# `, O' M5 w+ ]8 u" S
- }
) m. {) A0 U6 y. p - & F& X- ? M, j9 V# B- B8 q9 p
- /* copy the frame size table (2 bytes per frame), as a placeholder */
) T; f% B1 A" K$ X z - rbt->frame_size_table = malloc(rbt->frame_count * sizeof(uint16_t));
: q8 J# M. a( A3 D+ v7 l - if (fread(rbt->frame_size_table, rbt->frame_count * sizeof(uint16_t), 1, inrbt_file) != 1)
; I) ~2 h. \3 V' |# e - {
) @4 c3 g$ d- Z% j- P' f - printf("problem reading frame table\n");
& E. e/ x, o7 ^5 g' ` - return 0;) i& q. I9 L# M5 x
- }. Z1 c9 w9 N r
- rbt->frame_size_table_offset = ftell(outrbt_file);1 E F. C7 z- j; j1 t3 F# _
- if (fwrite(rbt->frame_size_table, rbt->frame_count * sizeof(uint16_t), 1, outrbt_file) != 1)
& R7 m4 [* Z W - {: P9 @8 ?& b3 ?, R4 K M- ]
- printf("problem writing frame table\n");+ F8 y% t: i; d" o/ ?* C
- return 0;! t& }9 }3 a( J ?; U
- }
* R; Z! P3 c/ t1 h* ?; O) V7 g: X - 4 {8 g: I$ `# y" r
- /* find the max frame size */5 c; b2 ?1 V- a5 `. n" d5 o4 m
- max_frame_size = 0;; J8 q! Q [$ a5 M- g- i% c
- for (i = 0; i < rbt->frame_count; i++)! v, w7 @$ L" r
- {
( } q' M) [" ]0 `+ {) K! L& R5 X+ c - frame_size = LE_16(&rbt->frame_size_table[i*2]);2 A9 L6 y0 `; G- C
- if (frame_size > max_frame_size)/ P [, ^* Y$ o6 K( O
- max_frame_size = frame_size;8 d, {- k% u: [" B+ ]
- }
% l4 D3 N0 u$ `- I$ v2 i7 t - rbt->frame_load_buffer = malloc(max_frame_size);
a& D- n) ~. \" _( l - + r# N5 D4 V! d+ S
- /* transfer the unknown table(s) */8 w, C0 W. Y' D
- if (fread(unknown_table, UNKNOWN_TABLE_SIZE, 1, inrbt_file) != 1)) ]) M1 \& {' Y6 m
- {2 G: _* [7 m4 B% F ]: v
- printf("problem reading unknown table\n");8 B& y4 A8 K: U& m7 z) [0 ]
- return 0;
8 Z5 V& |$ J/ F0 [ - }
8 D( ~0 Y0 u% j' g+ S0 K- t6 Y - if (fwrite(unknown_table, UNKNOWN_TABLE_SIZE, 1, outrbt_file) != 1)
) i- l+ Y* Z9 b- v z - {' N' Y1 ]* M4 R% _$ S' Y7 E
- printf("problem writing unknown table\n");
* u4 i! {6 d- s - return 0;
$ w0 P( o. f' L! j; v8 r0 m6 o - }
+ D3 A- B5 E# ?- l - 6 d: D9 }! q% I4 r) n' \
- /* copy over padding */
. Z$ Z2 @5 W9 ?1 e - padding_size = 0x800 - (ftell(inrbt_file) & 0x7FF);, ~- d, R4 o/ y7 T% X
- if (padding_size)
; U( [/ O6 E2 c7 S - {
' I I- ^' N* k# J) g9 n/ S - padding = malloc(padding_size);
$ W. h1 M/ T$ N2 v4 A+ h2 N - if (fread(padding, padding_size, 1, inrbt_file) != 1)0 N( W9 p/ ]7 W# b$ G
- {1 s6 [" o8 M- f4 \6 R
- printf("problem reading padding\n");
. X5 r; y4 U! f+ S8 F; t - return 0;
0 U4 i0 j9 j5 {, A2 x9 P - }
, _: k/ Q m1 w8 {8 J - if (fwrite(padding, padding_size, 1, outrbt_file) != 1)
7 a0 N# m1 Z: [" c0 o/ f - {
5 _/ g4 o* E. C9 b+ t' P$ P - printf("problem writing padding\n");* d% W' \1 V9 \; w' Q( D$ X
- return 0;% q C2 V7 [" D+ Z+ F) g) J( B
- }' C' {$ [ c5 C. c
- free(padding);
& u1 ^+ W( R" B7 }' |; X - }1 h+ i& y8 Z% p8 i7 U
( b T. `8 Z- n8 B. g* b8 }# o$ b# V- return 1;0 P" h! d1 J0 b% o: ^
- }$ x) B& q: `% m& _# N
- : U9 n: q: B4 `# l) v
- static int get_lzs_back_ref_length(get_bits_context *gb)
2 g% d e3 y9 }4 ^( q! W+ Q - {! q/ R, K$ S# L( P3 K+ y* X ^1 e
- int vlc;: G% r; _3 C5 D) k9 I! i4 g
- int count;! l! J% w1 v' W" g
- int value;
% k1 Z0 ]2 [* r - * O; s1 h/ g3 R
- vlc = view_bits(gb, VLC_SIZE);9 R7 U7 N0 o# J: h
- count = lzs_vlc_table[vlc].count;+ V8 k7 O& P+ z
- value = lzs_vlc_table[vlc].value;8 o. h) I! M3 M" Q
" i& s3 R1 Z, b, `2 y7 T6 Z7 ]% Q- read_bits(gb, count);: i# ]' j* O0 u
- if (value == 8)6 ~' D. H. f8 ^! {
- {. m* p6 t) a" d0 x7 B
- do& x$ Y6 c7 e6 W2 }
- {
6 o' H ?4 a; ^: C/ u, e - vlc = read_bits(gb, VLC_SIZE);' ~# j, X2 g8 `5 ^# m" v: y9 o& r
- value += vlc;
( h' X. v! Q; Y% I6 T - }& u8 x, u; I4 Z( V/ }' _
- while (vlc == 0xF);4 q3 g7 t/ a3 N. {1 i/ Y' q
- }+ d. E+ b9 F2 U9 _8 ~/ f; E2 n
: O! J( g: p# M# \1 h$ v7 T' R- return value;) F5 o" c7 F, [* n
- }: w) q6 v5 `: t+ j
, [- w c; F6 k+ I" T' T* r- static void compress_window(put_bits_context *pb, uint8_t *full_window,/ n; s0 `; o$ e r& h v0 n
- int full_window_stride,' V6 n7 c3 y6 Z3 R s E
- int window_top, int window_bottom, int window_left, int window_right)
3 n" d4 { k& H" c! [( W - {
! F9 }4 n! }/ c' p8 D# c8 W$ G9 W - int last_pixel;
4 T( W. v, |! J3 Q3 ?7 f - int run_size;
1 X9 z/ E5 J7 O0 } - int x;
1 I. w0 D+ Y8 O0 o& _: h3 ~ - int y;
5 z5 o/ _+ v3 k8 H- j& g. M - int start_index;
; R5 e/ z$ A1 _! v! y0 w9 w; h$ ], ~ - int end_index;
, |+ n$ ? S" b6 D' l7 X! u - int encode_last_run;, w3 t5 q) B/ G' j( ?2 n& ]$ T* Y
( V6 M# L' p5 a- last_pixel = full_window[0];
/ k; C8 O+ i8 p8 w; { - run_size = 1;% Q( {/ t! ]: |
- for (y = window_top; y <= window_bottom; y++)
& B6 U7 N7 n( s. d8 a( i, h - {
% N2 R5 \( a4 i' X - start_index = y * full_window_stride + window_left;7 {6 W z2 z7 [, Z. @$ i' |! |
- if (y == window_top)
8 N- D# B1 x) r3 X+ I5 ^ - start_index += 1;
. s# H$ i! m6 ~4 W% K - end_index = y * full_window_stride + window_right;! z% G# V6 p; `; ^. F, i* X7 \
- if (y == window_bottom)% Q0 j9 v- |$ @# f
- encode_last_run = 1;
7 z& f6 l* f7 S6 ]' z& ~# n - else
2 M, X. D% T! J7 c( o8 W - encode_last_run = 0;5 ?7 A! S5 ]9 g- j% x5 F: k% g
- for (x = start_index; x < end_index; x++)
3 l4 b& m8 I: M" V9 a - {) c: u* a: j& x( J
- if (!encode_last_run && full_window[x] == last_pixel)
. u* n+ x" O' F, l' p7 ^! D - run_size++;9 x' K* E* @9 T' F5 {4 I9 O
- else
( s+ l1 [( ~4 {3 O- ^ - {2 ~9 W" A8 M0 d
- if (run_size == 1)- W# k& S: O) Q. S. ?! e% a
- {
4 x/ @1 T4 g0 ~4 ^0 \7 E - /* encode a 0 bit followed by raw pixel byte */
- p1 h' ]; V" L- Y- v3 q - put_bits(pb, 0, 1);
v9 g/ I n' c$ o2 p% ?3 o' t9 n. K - put_bits(pb, last_pixel, 8);
$ X' Y7 D4 j5 c6 Z3 T - }3 Y% h0 p% `0 j% O4 O
- else if (run_size == 2)5 M3 j; N4 W# M( t
- {8 o. C" A8 c/ z4 K
- /* encode a 0 bit followed by raw pixel byte */8 O3 l% X) L# B" ]' d+ e
- put_bits(pb, 0, 1);9 ~% h6 W, w+ J- N" k/ e) H, c
- put_bits(pb, last_pixel, 8);
: Y5 h: b' {- |0 R+ r4 e$ w- k5 z - put_bits(pb, 0, 1);
5 D* }' x" L4 S+ V5 g: O! } R - put_bits(pb, last_pixel, 8);
! G s; w3 S, ^9 I4 _! m3 R- P. ? - }
+ f) V |* f/ X3 `" B# Z: s/ e1 D - else
/ [# J2 T/ i( z. V, _" `* n - {
- j6 v& U% P% R - /* encode a 0 bit followed by raw pixel byte */
" _( d5 i4 Q: s* r- |8 D( { - put_bits(pb, 0, 1);. u8 p# ~' }2 ]$ Y, J7 M% E8 J1 K# Y
- put_bits(pb, last_pixel, 8);) C4 e# r3 M. M) Y4 s
- run_size--;
3 R- k) t L6 a G! W$ m- Y" b( v9 v( P - /* encode a run: a 1 bit, followed by a back reference
0 w! g# S4 ?4 K& F - * offset (-1), followed by a length */
' p! C* B) a( X' \ - put_bits(pb, 1, 1);8 t( o! z# w! n
- put_bits(pb, 1, 1); /* 1 = 7-bit offset */2 w1 z( D, G; r! c
- put_bits(pb, 1, 7);; }( Z1 @* H% I9 g) ^ |" a
- if (run_size <= 4)
) ?; p9 A: K; D - {
7 b7 x0 j2 k4 o/ }3 h' H) t - /* lengths 2, 3, and 4 are 2 bits */
, j1 B( v$ \# l1 R4 I4 s. Z - put_bits(pb, run_size - 2, 2);
0 o/ W* Y+ [& F- ?9 n - }" g/ R8 g3 J, k" u
- else if (run_size <= 7)
0 @/ x. f4 ~ j8 T - {3 E# H4 u$ a& O/ ^+ Q) b0 G
- /* lengths 5, 6, and 7 are 4 bits */
7 f* V+ }5 n0 Q: K7 G- T - put_bits(pb, run_size + 7, 4);
8 B# V m5 J ~ l" z% R! ^4 m - }
& ^* U1 r, G! [( f7 |, J - else2 Y, |3 E$ {6 f
- {0 N' q( d( s5 i, Q8 D
- /* arbitrary length; start by encoding 0xF which
* J3 d. r# H" _) ~4 u" d0 P+ k- ~ - * stands in for an initial version of 8 */" g, t" F, c7 I% R/ F, |% \
- put_bits(pb, 0xF, 4);5 r4 X3 C7 w- `
- run_size -= 8;
6 a. H2 j' B4 L2 ]& p
- U, l% U' w b- /* encode blocks of 4 bits until run_size is 0 */
! ?4 _. \1 l3 f5 r - while (run_size >= 0)0 y, W* P* L$ ]$ Y- S
- {4 ~) D" q2 ~1 e7 F: v
- if (run_size >= 15)
# \0 h! S: \) v) T8 t( } - {
" U: F6 t- d& I+ c5 W. U - put_bits(pb, 0xF, 4);! R" G3 n3 Q( ^9 y( Q. g# N
- run_size -= 0xF;( Q% v, u! m4 M
- }! A. o* D7 }( g) V8 Q6 a
- else T! Y& z( [ G- H
- {
* I8 l: I2 w$ K. H* E: W - put_bits(pb, run_size, 4);7 j! S3 U: x% @
- run_size = -1;6 N3 s( r/ R, ]$ j) s2 E
- }
2 A) v+ i s% b* f Z - }+ {6 B$ `. F% B0 P5 Y
- }) U1 _- e' f. _' s# G$ k' k. t
- }: p, {7 R$ j$ ~$ B% j3 h
i6 F: T8 I% u- last_pixel = full_window[x];
b- Y0 @2 v5 m- y' D' U - run_size = 1;
1 P) C' _: d5 q5 p1 T$ M! q4 _
; _2 ?( ~5 X) ?- /* this single x iteration was only here to close the final run */0 A) g1 f7 `8 k5 l+ D+ Y
- if (y == window_bottom)
x, Y4 D- H( B, C/ `# P - break;
" y0 T# L* h! h* l h- Z - }
' G0 ]. C( K& b1 W+ J6 s - }
c- f& ^4 Z" V# h- } - }
3 j; v3 p. U) H, S8 Q2 I
9 ?% W$ _4 i( I+ C4 ~- /* close the bitstream by encoding a back reference with length 0 */
- d. i/ Q3 g/ X% x/ w( y8 c - put_bits(pb, 1, 1); /* back reference run *// w- |7 ]- G4 x* ?3 J
- put_bits(pb, 1, 1); /* 1 = 7-bit offset */
4 D9 H f8 K0 w6 K1 K0 s/ J1 _+ A5 ] - put_bits(pb, 0, 7); /* length 0 */7 j) C n0 W7 _! ?8 o7 E0 G
- \4 s9 l3 \. N/ U! v X
- put_bits_flush(pb);
6 }- V- O8 [" j2 Y4 W$ U) n - }) L( i" l7 v p" G9 ^
+ g ]* s. n9 Q- S4 F3 \- /* compute Euclidean distance between an RGB color and the desired target */3 W" P9 V) _. r% R7 b
- static int compute_rgb_distance(int r1, int r2, int g1, int g2, int b1, int b2)
$ X: L( O3 W* k - {
6 e4 w# d; o0 a - return sqrt((r1 - r2) * (r1 - r2) +
$ _0 O2 r x( ?0 c# D+ u - (g1 - g2) * (g1 - g2) +8 X5 ^5 T J, h4 J3 _# r$ a3 t1 L+ e8 g
- (b1 - b2) * (b1 - b2));
. H% r, [7 f/ J0 ^ - }$ R! X1 t. h8 e. r2 D# z) f
; a U9 @9 Z& l/ Q: @- static uint8_t find_nearest_color(rbt_dec_context *rbt, int r, int g, int b)
4 G+ i4 Y1 `2 ]! \9 J4 u - {
, S* S3 O3 n$ e0 N v) x m2 r - int i;
N% c* q! ?' D) ~ - int nearest_distance;2 O, W& M. Y" q! |4 Y
- int distance;
8 V3 P& b. Q6 t( e! ~ - int rp;8 w2 W+ ~3 L2 h c! `
- int gp;2 ^/ p0 R) k7 V$ Y4 Y! o9 F# O t( V
- int bp;# H6 ?3 f1 u3 A
- uint8_t palette_index;# W* F0 s- B7 H2 d) a5 u
% q# [& f w7 c$ X5 a- c; T- nearest_distance = 999999999;
3 ^& v) `$ A& n" g7 z$ ^ - palette_index = 0;
9 X G5 i" f& }4 L# F3 | - for (i = 0; i < 256; i++)
! m! i: l: ^5 ^6 _ q2 f- c - {( F \0 s' W* N l, O
- rp = rbt->palette[i * 3 + 0];
) t* S4 H4 t/ F) z7 s h - gp = rbt->palette[i * 3 + 1];8 Z& p! O1 Y% q6 _% M/ v
- bp = rbt->palette[i * 3 + 2];& ` P8 u6 t- {# @6 j! o2 z) @9 k6 O" W% g
- distance = compute_rgb_distance(r, rp, g, gp, b, bp);/ g, t: t' |: @
- if (distance < nearest_distance)6 |+ }/ H( i* X
- {6 d. q! q9 J9 I! X7 W8 U* C6 {
- nearest_distance = distance;. K: T& { z; B; [/ ?* f( \
- palette_index = i;
3 q. ]* {& D9 Q* @8 }. W4 N - }
, W$ R3 m8 g( n/ R) H( J; ]& q/ s! L - /* can't get closer than 0; break early */ ? Z9 _, W# U) z/ T* R
- if (distance == 0)
" ^- Q" \ u$ e. y/ ]: j, G3 Y - break;0 ?- M. M6 P. ]3 {2 ]- F, s
- }0 Q# g/ Q4 w! M/ a
% c, |7 I2 \8 v* Y, J- |- return palette_index;/ y3 W* r! Z/ w+ m
- }
2 ?2 N: W2 v" u U& p) p
1 l4 y2 w" W: I% |4 { z- static void subtitle_frame(rbt_dec_context *rbt, uint8_t *frame,/ S! ]8 y9 v: q0 F+ J
- int width, int height, int timestamp)
9 u8 f6 w: m. m4 u - {8 D; K5 ^1 Z) A1 g G9 K$ @$ B9 a" d9 c3 _
- ASS_Image *subtitles;
+ [- R! n/ k: t: y, |$ { - int detect_change;3 J$ F+ D9 X7 }# d% s4 W
- uint8_t subtitle_pixel;' l) ` ~& Q5 x
- int x, y;3 N2 {7 V2 G; P4 x* d$ O& M# G
- uint8_t *frame_ptr;
. A2 A8 b' t8 L% ^! ? - uint8_t *subtitle_ptr; h7 D4 Q6 i& O* N! g7 o2 a7 O
- 3 f! c+ M0 _$ ~
- /* ask library for the subtitle for this timestamp */1 Y4 Z. p1 C; w& c2 E n
- subtitles = ass_render_frame(rbt->ass_renderer, rbt->ass_track,
1 b5 }$ u1 x% g; L - timestamp, &detect_change);% X) @" l' [* ~1 T2 E! s# i
- 6 Z- V" y: x( p
- /* render the list of subtitles onto the decoded frame */
; o7 M8 e6 f6 [" ]7 ]3 `6 V - while (subtitles)
, V+ N; ?0 Z, Q4 Y, h% y- `% |2 k, F - {9 E+ c3 n% I3 @* n% M; u
- /* palette components are only 6 bits, so shift an extra 2
5 ]3 [8 A4 q! Z1 R - * bits off each component */
! n' _: ` d- A8 T+ _! j, z - subtitle_pixel = find_nearest_color(rbt,
/ l- g* d$ o! ^% G, E+ n5 ^) y" @ - (subtitles->color >> 10) & 0xFF,( J0 r6 ], ]: D9 M0 r; @
- (subtitles->color >> 18) & 0xFF,# h. s( z3 c* }/ L# G) E
- (subtitles->color >> 26) & 0xFF);0 w6 ~8 |6 a6 c" _
- for (y = 0; y < subtitles->h; y++)
" X7 h4 a* G- e& `7 p - {- p. B/ {1 ?" a
- subtitle_ptr = &subtitles->bitmap[y * subtitles->stride];
' S _# d1 a, `' j/ H - frame_ptr = &frame[(subtitles->dst_y + y) * width + subtitles->dst_x];: G8 s( g& p$ ]) S. c+ s- U
- for (x = 0; x < subtitles->w; x++, frame_ptr++, subtitle_ptr++)
8 T+ t6 D0 v: t: r4 c" i# R4 \ - {# u1 Q( m! D- ~
- if (*subtitle_ptr >= SUBTITLE_THRESHOLD)3 ]6 h3 J; g' |* J) Y" ]
- *frame_ptr = subtitle_pixel;6 e7 O$ ~0 n- n3 t3 J% T7 D0 `$ F
- }" }6 b) E7 Z% Z; B0 V
- }
4 o% g( M5 H# u) a+ ] - subtitles = subtitles->next;
% w r7 m! y: W# F+ t8 y5 Q. f - }
6 G* i3 V6 ?5 T" k2 }/ `% C/ \ - }
3 P% a/ n% y) g7 Z" C
/ i! v/ b0 S* N, |4 e: u0 J7 g- static int copy_frames(rbt_dec_context *rbt, FILE *inrbt_file, FILE *outrbt_file,
, m) `9 W4 r e# ?- M! @9 g - int origin_x, int origin_y, int window_width, int window_height)* O9 G v. A D- J
- {
& k$ t7 P5 D7 |; |* h. H6 b - int i;3 f/ D1 n: h# A
- int j;) h3 b6 l, d( x% C+ f1 k8 I& ]
- int scale;9 u0 q' d+ k8 V& n5 p
- int width;
6 h' X& l9 E- _7 w! O - int height;
6 h$ O5 W6 O( k# B. z - int max_width;
, D$ [9 ]* [; U4 c! d: Y - int max_height;
) g- b- a- S# g1 y9 F* { - int frame_x;1 s9 b8 o. \/ g' ]+ ?5 M
- int frame_y;& f: a- ]" g5 |9 \+ f* I) D" |
- int fragment_count;' Z( q: \$ {, r) G0 G
- int decoded_size;4 `( D( y1 [5 ~
- uint8_t *decoded_frame;
; e( }' |, K" @4 h0 ?1 C - int fragment;
* D% { G! P( F+ N - int fragment_compressed_size;% B' ]$ [' @6 j6 I
- int fragment_decompressed_size;
" m( V- E% r2 D - int compression_type;
8 {. k$ v/ y/ ~2 Y - int index;
" {" |, s2 v; F1 A6 I$ o5 n N7 f* s3 q - int out_index;
7 C+ v& ]8 O2 e4 _ }5 H( l - get_bits_context gb;7 [' y; `- C( O: p. {; Y( v# [) C
- int frame_size;
# R0 }% w) Y" } B3 M - int video_frame_size;
+ i7 c, |7 I% c6 M - int audio_frame_size;
: b4 G8 T6 `0 X; W4 |4 E/ S4 v9 Z/ L) o - ) w" v/ z K# c* i9 ^% H- F
- int back_ref_offset_type;. W. @$ V- F9 _5 V
- int back_ref_offset;; |; E" H$ x& P
- int back_ref_length;
2 `$ z: Z9 Z! d$ E- |1 w8 i, k - int back_ref_start;
- k& i+ ~+ D# [' k7 P; _ - int back_ref_end;" p; r. }, L( w6 E' y/ ]. |9 \
2 H$ c: c7 o5 S$ U5 K0 F" o( h/ q- uint8_t *full_window;" Y7 C: Z2 w0 f# U& b* Z/ g" d- ?
- int full_window_size;; q" s; S# o: d# c5 Y
- int y;
9 O1 r1 t4 g- Y# K. z6 z8 v$ t% [ - int window_top;
. U3 w: d1 L: @3 p2 ? - int window_bottom;
# f6 b- v" p) l6 ~2 _& U - int window_left;/ Y1 v+ i, q* |8 d
- int window_right;
5 n3 [0 f1 F3 i# e# J) N - int window_size;2 c# E# E" f! H* {* y2 h
- ! ?9 T! ~( Y" d S; U' l" X. C
- char filename[30];& E% o* N. ]) j; H& ]9 _
! Q; W5 W0 S- A- put_bits_context *pb;" S" j# _0 C; Z* X2 @( ~* W( ?
- , J# N/ ]1 i+ K4 Q% j9 s Y
- full_window_size = window_width * window_height;
# N. h1 j* {5 R - full_window = malloc(full_window_size);( F' A9 K9 I* c! [! e. k
- pb = init_put_bits();- E' r$ D8 Y9 q. T, n: v2 b
- 9 n4 K# L1 O# ~. B) k3 b8 I+ h
- max_width = 0;
* C7 G$ R( n# |6 I0 M2 N, A/ } - max_height = 0;! x) L k5 I5 A8 K3 v6 p* C* L- Q
) a4 @1 @& o. E F; e, [9 |- for (i = 0; i < rbt->frame_count; i++)5 F, a# {. j2 y0 Z# y. g/ ]
- {7 C" } [- F; K. ], p6 {- i
- /* read the entire frame (includes audio and video) */
1 V* J1 `, Q J: _1 D- }( n# L+ M - frame_size = LE_16(&rbt->frame_size_table[i*2]);
; T) e _; X& O3 J! P+ d8 g/ V( q - video_frame_size = LE_16(&rbt->video_frame_size_table[i*2]);# K7 W$ y' X, }( s8 t) H8 x! h; N
- audio_frame_size = frame_size - video_frame_size;8 n9 e( W B" m- y- c6 s
- if (fread(rbt->frame_load_buffer, frame_size, 1, inrbt_file) != 1)
) ~/ \! n3 e3 }) E+ \# p6 _ - {
* J2 b. I4 x$ g- n- d0 v - printf("problem reading frame %d\n", i);
* h- n+ c% D. |) z+ d, o - return 0;
$ l, r9 G6 f! D( K- Y* w3 V/ t) w/ \ - }0 E3 X! W, m, o
% u0 H# ~9 z( S+ l& \2 p V1 \& m- scale = rbt->frame_load_buffer[3];: g7 a9 j. A b9 B+ W
- width = LE_16(&rbt->frame_load_buffer[4]);7 ]' ?7 y8 D3 q! `
- if (max_width < width)
3 w5 e7 z& ~3 I) N, e7 j - max_width = width;& s( n& O+ v3 {2 F* D% D! Y) h1 }
- if (max_height < height)
/ B/ w; g3 }; m$ r6 [3 Z - max_height = height;
8 ]% W# }8 a! f" X- U6 X1 L - height = LE_16(&rbt->frame_load_buffer[6]);
1 z6 C" Y7 [3 ?" A0 D+ T* g9 b - frame_x = LE_16(&rbt->frame_load_buffer[12]);6 x. H) r! i! S4 U# e% u
- frame_y = LE_16(&rbt->frame_load_buffer[14]);
2 o6 w# ~8 W9 Q6 Y8 r7 E" a: V - fragment_count = LE_16(&rbt->frame_load_buffer[18]);
. E6 w: | I0 A( @ x - decoded_size = width * height;8 s+ C: g; H3 ~) h# j
- ) F* l4 X6 ]; I2 |/ z4 F3 o+ L
- printf("processing frame %d: %d%%, %dx%d, origin @ (%d, %d), %d fragments\n", i, scale, width, height, frame_x, frame_y, fragment_count);# e* J$ ^3 K+ ]$ ]" a
- % V4 K6 f! \% T9 e* `! s" I4 L/ z
- /* decode the frame */
) T+ k1 |) f( W. H% b1 F& g2 _ - decoded_frame = malloc(decoded_size);% Y k; N. d6 e6 e4 b/ W/ M
- index = 24; n" w' [8 W0 \+ ]9 Y4 B2 e* U) [
- out_index = 0;% }3 _ ~5 K# d r4 \- \
- for (fragment = 0; fragment < fragment_count; fragment++)
) y$ {! k! n4 O - {
# Y* @5 W# @3 o3 M3 v3 E - fragment_compressed_size = LE_32(&rbt->frame_load_buffer[index]);
- Z" b4 l/ I+ ^& t) F! ^7 O - index += 4;( H; _ @3 Y: J% z/ k
- fragment_decompressed_size = LE_32(&rbt->frame_load_buffer[index]);
" s/ k6 J; |, p+ a& e) d - index += 4;
( @! c, i0 q9 U( w8 N/ J. o0 P5 W# J - compression_type = LE_16(&rbt->frame_load_buffer[index]);/ T0 a* M: a- p4 Q/ v
- index += 2;; E5 J2 S; i1 J$ A& N9 K1 R T) W
4 I8 Y8 R( C, @3 j1 A6 u* o- if (compression_type == 0)
) b# F2 H, n, P; i" q. w% p - {
$ U1 y2 V" ~+ w* x2 _7 O - init_get_bits(&gb, &rbt->frame_load_buffer[index],7 A! I- v- c$ A, @0 w" a' w& l
- fragment_compressed_size);
* \ y6 }+ k: o4 I) ?0 ~6 f
; K @0 ^# \8 }$ L- while (out_index < fragment_decompressed_size) [. n3 W* K" E
- {, }# c- d2 h" V
- if (read_bits(&gb, 1))8 C$ a5 j: A/ V
- {
8 r, v. Q4 G, N/ Z: n& [ - /* decode back reference offset type */) H% [( c, p# K
- back_ref_offset_type = read_bits(&gb, 1);& v0 i* c' r9 l2 v: I6 M0 w
8 Q+ n, n5 s3 x) j% x- /* back reference offset is 7 or 11 bits */
% t5 w7 }: O9 J% A2 P3 E - back_ref_offset = read_bits(&gb,; O1 N7 R- }# P4 Q6 M2 s+ }/ v6 A
- (back_ref_offset_type) ? 7 : 11);
; G! d& Q U9 ^8 U W4 Z3 m
) |$ G t+ X& ]- /* get the length of the back reference */& e% e" m" N# S( z! |% W B
- back_ref_length = get_lzs_back_ref_length(&gb);
/ D k! O7 V+ N; z- d - back_ref_start = out_index - back_ref_offset;
' O3 @, j/ k# H' N' M) d, | - back_ref_end = back_ref_start + back_ref_length;2 q0 G" q: p' l8 |1 {
- A, O& z% y% d% `7 G) Q! u
- /* copy the back reference, byte by byte */
8 k$ S# R6 b% @ u5 T2 p1 @, w - for (j = back_ref_start; j < back_ref_end; j++)
: n8 B* `/ N% `2 x - decoded_frame[out_index++] = decoded_frame[j];5 [- Z# P: w5 G5 e4 G( s
- }' U' s9 i; D6 D$ ?1 M; r F
- else
9 f2 `: g) Q% R% y$ j+ f1 h- g - {* E3 N0 x/ H$ o) F) ?: L
- /* read raw pixel byte */$ u) _$ {$ E% e# U% e8 G% k) h8 z
- decoded_frame[out_index++] = read_bits(&gb, 8) & 0xFF;0 y- `% i( m0 V% l; b+ W$ g* m# |
- }
7 {$ E/ d) V- P- I/ J/ R - }
2 b2 G5 Q0 D/ T) i Q1 x - ' E# N( B% V5 k( P. S3 c
- delete_get_bits(&gb);0 S+ C6 m: x0 n) S0 y; A) O
- }. Y4 a& m1 A! F& m! b* F k9 F6 M$ h
- 4 q% m0 X/ Q! x, L8 I' S% [
- /* next fragment */6 X) }8 T; n' k" l( N
- index += fragment_compressed_size;
- m; f1 J& K$ l1 a; H - }2 H8 F1 S, G$ B6 Y
) D( c) f" v, r, K& H- if (rbt->dump_frames)% F# L( U. f' | x2 A8 l7 u. x
- {8 Y1 M- ^4 ?6 L0 ]4 y
- /* dump the original frame */
# m7 V" ]2 b7 F' n& c3 ^0 h% d( N' i - sprintf(filename, "original-frame-%03d.pnm", i);
% X' T/ E; ]5 ^0 t, [' y; u/ O - dump_pnm_file(filename, rbt, decoded_frame, width, height); A. {& v+ v- x
- }
+ B3 z+ [9 l- g2 G/ t' @
1 |$ w' u8 g' O; Z% W& |$ C- /* transfer the image onto the frame window */( C* R) ?$ O1 S' O' Z' J3 Q
- memset(full_window, 0xFF, full_window_size);, {3 N T; y2 G& C2 @* ]
- index = 0;6 X& L! M' [ Z2 N
- for (y = 0; y < height; y++)1 P- _: `' U: r+ T% H
- {0 }. c; }, m2 A+ ?* S# L
- out_index = window_width * (frame_y + y) + frame_x;
' |3 q# |1 w6 p4 Y1 {' E - memcpy(&full_window[out_index], &decoded_frame[index], width);
7 W r% M$ V! D( s - index += width;" ~; C% o% C) y! F
- }
) q9 ^: d! j* m& Q! {0 D
9 h7 v7 W* B- Z2 M4 V6 A: m* a- /* write the subtitle */
; D: x5 g& g+ U& ]. G+ q' ?6 p - subtitle_frame(rbt, full_window, window_width, window_height,$ Q( d) b' k8 ]: S
- i * MILLISECONDS_PER_FRAME);
4 S* r7 Z9 V, |) { - " Y, [8 P2 ^" m' C1 {0 G5 k1 _
- /* figure out the smallest change window */
$ ^! ^' z: g6 Y& _# L4 n - window_top = frame_y;, U! o3 {& ]3 d! Q; a
- window_bottom = window_height;
; B4 |& p9 S4 D( U- ` - window_left = 0;3 \3 x8 S ] U. D
- window_right = window_width;& Y2 I3 v: `1 K& ?7 M1 \7 u1 U
- window_size = (window_right - window_left) * (window_bottom - window_top);1 M/ U5 O4 W. I, \
- % s/ d: \( ]/ @6 a+ D
- /* compress the frame */* o) E4 U$ N" o' p
- reset_put_bits(pb);
: n& a, U0 v- o; z - compress_window(pb, full_window, window_width, window_top,
' t% d2 D O7 u6 B2 u - window_bottom, window_left, window_right);& U4 C! I$ h9 j' t
1 T$ V8 ~+ S/ s( X2 z- if (rbt->dump_frames)
& t4 f* w0 ~# h2 d4 F - {
6 m! j4 K1 q* D% l! F" m1 h1 a - /* dump the frame plotted onto the full window prior to encoding,
* C, o3 a& Y* l2 I4 O. t/ R - * with subtitle */1 k, n/ t# a9 w, N
- sprintf(filename, "pre-encoding-frame-%03d.pnm", i);8 @( C z: K% g2 E
- dump_pnm_file(filename, rbt, full_window, window_width, window_height);
' p' \! a* y a1 ~% B - }
/ w) P9 w! T# }0 Y - " v9 E/ X1 ~, F4 D' D! T7 ^, I
- free(decoded_frame);! w4 m$ L9 S" h3 u) i7 y) g% V
! F2 g& \- Y# ^) C1 ]! ^% y6 l# c7 c- /* update the frame header */
$ Q) A* @( d( o$ S0 `! Q! @ - /* width */& V5 p7 }8 u3 R* ?+ H: c+ S0 U5 i( U
- rbt->frame_load_buffer[4] = (window_right - window_left) & 0xFF;
7 i: B& |5 ]4 {5 Q' D, e: A. M - rbt->frame_load_buffer[5] = (window_right - window_left) >> 8;
% {7 Y. }5 c7 y9 U# \7 G* M - /* height */
' ^( H$ ?9 `0 X. R* ~1 b- v& l' r4 ]- e - rbt->frame_load_buffer[6] = (window_bottom - window_top) & 0xFF;$ i! R6 c% S2 M8 u! a* b% _
- rbt->frame_load_buffer[7] = (window_bottom - window_top) >> 8;
6 `( k8 J. E ~4 N9 O7 S - /* origin X */$ ?* w; i2 _# b8 ?; R
- rbt->frame_load_buffer[12] = window_left & 0xFF;& T T" P2 @5 u: r$ c3 K! b
- rbt->frame_load_buffer[13] = window_left >> 8;0 [, K; P) v3 i$ H: F; ^- `
- /* origin Y */
4 @: Z# ~) M: N& a$ Y6 x7 S - rbt->frame_load_buffer[14] = window_top & 0xFF;! C/ p3 A$ l; m2 |- H9 ~( y
- rbt->frame_load_buffer[15] = window_top >> 8;/ Q% {9 e* d- \1 @
- /* fragment payload size */: }) g$ k& h; o6 Q" o7 e, k
- rbt->frame_load_buffer[16] = (pb->byte_index + 10) & 0xFF;! C- @$ K8 F' }4 z: V
- rbt->frame_load_buffer[17] = (pb->byte_index + 10) >> 8;
9 I7 f2 w8 k! Y- S' ] - /* fragment count (1) */
! ]8 b% u6 l( R$ c: y! E6 l - rbt->frame_load_buffer[18] = 1;
2 t3 B k: ?4 A/ \+ d - rbt->frame_load_buffer[19] = 0;
, K1 c3 _1 ? E a/ H8 g$ v* a
7 t- I+ W5 `( y5 w# v' e- /* update the fragment header */
8 @1 Y0 T) U6 H - /* compressed size */
4 v- y$ V& E! ~ ^' i& W: L - rbt->frame_load_buffer[24 + 0] = (pb->byte_index >> 0) & 0xFF;+ U d, I- m4 d+ @4 b+ N6 }7 }
- rbt->frame_load_buffer[24 + 1] = (pb->byte_index >> 8) & 0xFF;
5 `/ L) }5 o7 a+ n: Q - rbt->frame_load_buffer[24 + 2] = (pb->byte_index >> 16) & 0xFF;6 p0 [! d% ~ j4 n
- rbt->frame_load_buffer[24 + 3] = (pb->byte_index >> 24) & 0xFF;+ e6 n/ G; Y; G$ s+ N
- /* decompressed size */' y1 W& q0 X! ~7 F3 `
- rbt->frame_load_buffer[24 + 4] = (window_size >> 0) & 0xFF;2 V u2 A. w) X8 f
- rbt->frame_load_buffer[24 + 5] = (window_size >> 8) & 0xFF;6 N( B2 u/ D D' s7 O
- rbt->frame_load_buffer[24 + 6] = (window_size >> 16) & 0xFF;! h* ?2 b [+ U
- rbt->frame_load_buffer[24 + 7] = (window_size >> 24) & 0xFF;! [4 B" X1 U: ?& j2 G
- /* compression format 0 */
+ \1 v7 p3 n) e C0 N# E+ Q7 x - rbt->frame_load_buffer[24 + 8] = 0;
: m% T/ C1 D- h( v" C; i% R, U# O - rbt->frame_load_buffer[24 + 9] = 0;$ N/ z1 w* p& r; l
- 8 ~* h+ A1 j/ [- [& ^: r
- /* write the 24-byte frame header and the 10-byte fragment header */1 y$ K; w _* D! t8 F
- if (fwrite(rbt->frame_load_buffer, 24 + 10, 1, outrbt_file) != 1)
. E0 q V6 g* C - {
9 d8 z u2 M9 }6 U& ^; x - printf("problem writing frame %d\n", i);
$ d' x4 k* C# t j4 S7 h - return 0;# m8 J. ~1 f! Q9 N* y8 {
- }& S( D7 N: e7 u4 o
: n9 s/ E6 |9 b% _- /* write the new compressed frame data */
$ G0 Y6 l/ x# \1 f# j - if (fwrite(pb->bytes, pb->byte_index, 1, outrbt_file) != 1)( B) I& _0 W, u; `* T" R
- {
5 A$ X' l2 R* R* d( i - printf("problem writing frame %d\n", i);
$ Z+ s$ j" @1 ^! f4 k) _ - return 0;$ _4 S; D) F$ e# p) m
- }
$ N1 P6 R) Q8 w- L( P+ ]# g - $ k( C m2 Y( d# z2 }
- /* write the audio data */. y* B9 p2 V5 V* b' m1 K; X
- if (fwrite(&rbt->frame_load_buffer[video_frame_size], frame_size - video_frame_size, 1, outrbt_file) != 1)& B @" Y* o* o. \) Y$ |- w6 }
- {! W) S# ^' j# e: [. }0 I
- printf("problem writing frame %d\n", i);
3 F: x! w8 T' t - return 0;
2 l) z( ^- W) K4 t N' d3 [ n# J - }
. |3 r' H5 m- W& `/ O
i0 \- X6 v3 K# ^- /* update the table entries */
& Z' H0 W+ I' y7 v+ z/ B - video_frame_size = pb->byte_index + 24 + 10;9 u. L) V- l! ]( ^$ B4 k
- frame_size = video_frame_size + audio_frame_size;, u8 d# V. T! y( v" }* p& J7 @
- rbt->frame_size_table[i*2+0] = frame_size & 0xFF;
! v5 R# ?0 B m - rbt->frame_size_table[i*2+1] = frame_size >> 8;1 I, c% Q ~3 X
- rbt->video_frame_size_table[i*2+0] = video_frame_size & 0xFF;
* b x: B' I% }* t4 y, F' @6 c - rbt->video_frame_size_table[i*2+1] = video_frame_size >> 8;* t0 C5 F. [8 D- e& f: ]4 Z! q; h
- }
5 J; R6 d8 o5 M# y$ ]5 a# A
; @6 v1 X' ]/ `* _0 o: f; ^- printf("maximum dimensions seen are %dx%d\n", max_width, max_height);
( j/ W7 w+ T& s% N - A4 M1 `6 s J# w
- delete_put_bits(pb);" h! w Y- `3 q1 F0 K4 a L
- free(full_window);3 _/ j% u- h! f$ H( V: I! c
% B$ H% s. S6 y! h: Z- return 1;" G) m* X+ T3 R+ t
- }
7 M1 H) B: I& q
( J; [& }+ X, Y$ l- `' Z& z0 F- int main(int argc, char *argv[])
0 d! J- `) b0 S. k) [- u$ o - {
1 K4 g8 o- Q/ G# o f; W/ Q - char *subtitle_filename;, K' p' X, m. K" Z) g" ^
- FILE *subtitle_file;
+ `5 H. @# k, g: w$ \9 d6 I6 |/ I - char *inrbt_filename;% a1 g- x$ Z: u( V
- FILE *inrbt_file;
& V0 B1 A/ I" Y# b u - char *outrbt_filename;
+ q3 Z0 G. L- p6 z7 {4 i - FILE *outrbt_file;
9 m; V3 b( j- a0 B) d, ]6 x7 \ - rbt_dec_context rbt;
' S7 d) k. t7 | - int origin_x;
2 ^& k/ D/ z$ ?2 {$ y3 p0 _ - int origin_y;
) L% J2 I$ s v$ s - int window_width;
, n9 n$ ]% w" S3 z S - int window_height;! [, b' `0 S, e( Z d0 Y
, N% r! b/ p1 L% }- /* testing the bit functions */
O) i5 f3 _; H- \0 H8 V - #if 01 W" U F9 W7 o7 V
- int i;
( I* c( O! E9 u. a1 d - uint8_t bytestream[] = { 0x55, 0xAA, 0x00, 0xAA, 0x55, 0x77, 0xFF, 0x1B, 0x70, 0x8F };$ v6 f3 N: M% ?: Q/ K( n( u
- int bytestream_size = 10;" J# d, Y6 R0 {3 Z
- get_bits_context gb;
, z2 X9 M: r- ^% T0 u - put_bits_context *pb;
$ K9 Z: v/ ^* ?; C$ H2 l' M - int bits;
$ t3 |* O8 I# ~0 v - m' S1 C" n3 O
- init_get_bits(&gb, bytestream, bytestream_size);
5 g- ]6 i. u! T8 ]2 F X - pb = init_put_bits();
* x$ [. O7 X4 p W. @( X5 \. f - 3 U. n4 K0 r' d1 A+ h- G0 A
- for (i = 1; i <= 12; i++)
& }) ` }/ P! h3 D9 Y! c/ d - {
8 w2 q! _4 h7 S. F2 r- V8 M - bits = view_bits(&gb, i);# N! l( c: t6 D# s7 V+ ]8 c- P
- printf("view %d bits: %d\n", i, bits);
. b: ]4 u; v8 u/ u' d - printf("read %d bits: %d\n", i, read_bits(&gb, i));& S d: N2 }- z! d
- put_bits(pb, bits, i);
9 ] Z/ U/ }1 }8 N) u l7 c( W3 T1 t - }- }; c- I H0 d6 v6 z P
- put_bits_flush(pb);) S Z% q1 L8 B- Y
3 V, m* f1 c; l, g- printf("original bytestream:\n");
) P- T& E$ x/ [ - for (i = 0; i < bytestream_size; i++)) U; c& W7 n$ C& o7 p/ R
- printf(" %02X", bytestream[i]);$ @( _" u. m( t: A$ e
- printf("\nnewbytestream:\n");
, K+ O& U& o: u' t/ l - for (i = 0; i < pb->byte_index; i++)
6 l8 h* j, B/ y% J9 V - printf(" %02X", pb->bytes[i]);& Q! k$ ^' J# f& t) o0 t0 k
- printf("\n");
' j, ?) o- K9 L2 Z5 Y - 2 ^$ m' {1 s. V
- delete_get_bits(&gb);
- s4 q: r, M) r2 b# Z6 T5 X z - free(pb); P6 q$ _* ]& z
- #endif
4 O. g6 T$ e* H# M: S - , d( ?0 Z8 e9 S
- /* validate the number of arguments */5 u/ {- J) \+ Q2 Y
- if (argc != 8 && argc != 9)7 F; E0 E0 I0 a/ q
- {! }3 P- ^& g! c, G3 U
- printf("USAGE: subtitle-rbt <subtitles.ass> <in.rbt> <out.rbt> <origin X> <origin Y> <width> <height> [dump_frames]\n");
$ t/ l f; E% w2 H0 c l$ x; x9 v - return 1;5 g" M# T6 ]: |/ h
- }4 E2 W0 k. Z; @5 W
- subtitle_filename = argv[1];9 g& r" T. ]* K, ^, R+ v
- inrbt_filename = argv[2];
# N d, q1 e+ a% X) d - outrbt_filename = argv[3];
& e( [# i: e1 R- O t/ y - origin_x = atoi(argv[4]);
: I# n( f; I9 o3 k2 j4 C* Z5 ~ - origin_y = atoi(argv[5]);
9 J$ F% h8 o1 _+ }0 x6 R - window_width = atoi(argv[6]);
7 f4 |& R4 u# O/ N: } U4 n - window_height = atoi(argv[7]);- s& Z3 R0 [7 J! B3 ~' _
- rbt.dump_frames = 0;! A: N4 Z; q! N- c5 F
- if (argc == 9)
3 A. [0 R, @5 v. v - rbt.dump_frames = 1;
8 J" a" B( L& r3 d
5 p8 Q0 q7 x Q' R& u( C. j* n- /* verify that the specified input files are valid */
/ M3 |1 s# k7 V' b - subtitle_file = fopen(subtitle_filename, "r");
J) Q" q; y, }4 C - if (!subtitle_file)
6 u* G9 [9 Y; h1 Y3 J% R& h8 Z# a& s - {
7 f( U S- a# o9 ]* f - perror(subtitle_filename);
+ g0 ] W4 A: [& [2 `; E( z - return 1;8 U9 f+ [5 K! ^5 U# v% C( G
- }
8 F8 T6 |8 L% V) ^. [ - fclose(subtitle_file);
4 S, t7 H: M/ F+ E9 F2 M3 d - inrbt_file = fopen(inrbt_filename, "rb");. }- G5 x# n) L3 o- q/ Q- \
- if (!inrbt_file)! |" I* F1 Y& H7 q
- {
7 ~! F2 \) S2 R0 g - perror(inrbt_filename);
. G# Y. O- g0 |; `* i3 H - return 1;4 C- J# x: d4 @5 F7 n6 Q
- }+ R% Z6 q6 s. w) u( f% q
- Z: D/ d+ ?# L& _/ r3 d- /* initialize the subtitle support */- M% j. G0 t, l) D+ ~5 `
- rbt.ass_lib = ass_library_init();0 T3 V5 [( O, f1 z
- rbt.ass_renderer = ass_renderer_init(rbt.ass_lib);
: Y6 q4 W' _0 d8 g - rbt.ass_track = ass_read_file(rbt.ass_lib, subtitle_filename, "UTF-8");
# Y* R, s$ u5 a' `9 z K, v9 a+ c - ass_set_frame_size(rbt.ass_renderer, window_width, window_height);
' Z3 c+ w3 k0 ] E3 u+ G$ o - ass_set_fonts(rbt.ass_renderer, NULL, NULL, 1, NULL, 1);
% f1 k: l' a- j
4 n# J0 s- {# N$ J$ H* X) F! a- /* open the output file */
! _: {" }5 O) j - outrbt_file = fopen(outrbt_filename, "wb");6 z6 q" p' {. t3 {6 {" v$ n
- if (!outrbt_file)
# o4 D2 }- m6 @( L0 T$ ` - {0 E6 z( w8 y- Q7 i' h5 W: i
- perror(outrbt_filename);
* n# j5 E/ f- M1 \ - return 1;
* \9 \" g$ j# n+ h! T - }/ h3 i6 `: f: i0 I/ G' [6 a' @
7 s. v% D+ R2 b0 M* h [+ _. A- /* transfer header from input to output */
1 Q+ Y6 G) q# F# `, e8 n' Z4 C. S3 ] - if (!load_and_copy_rbt_header(&rbt, inrbt_file, outrbt_file))5 A0 C% z6 G$ N6 @/ U
- return 1;) j+ W _! D3 ~9 ~, c1 ~
- - Q- r, x' X# B2 K4 P
- /* rewrite the frames */
$ L' B9 s' i8 D" K! o/ N, F - if (!copy_frames(&rbt, inrbt_file, outrbt_file, origin_x, origin_y,
% N% _7 f7 O8 u+ e8 ^" V9 R; q - window_width, window_height))0 | D3 o) p3 e* }0 d* j; S! L
- return 1;4 t: F0 b8 m. }: ^. r- C
- 4 W* _" o/ j% G4 u8 K' @8 X$ d4 q
- /* write the modified frame size tables back to the file */5 C* i% z/ v/ v) o# m
- fseek(outrbt_file, rbt.video_frame_size_table_offset, SEEK_SET);
& j9 O+ w0 }# C$ j; A$ Y! D1 r# _ - fwrite(rbt.video_frame_size_table, rbt.frame_count * sizeof(uint16_t), 1, outrbt_file);$ \; I, q! c: k _) l) U5 Y) f
- fseek(outrbt_file, rbt.frame_size_table_offset, SEEK_SET);7 a% o, ?: z6 a5 U- A
- fwrite(rbt.frame_size_table, rbt.frame_count * sizeof(uint16_t), 1, outrbt_file); l9 [ j' W4 j6 n* s- i2 c+ g# a4 b
- & Z+ x) v8 x; O0 N x" b" J% f9 L
- /* finished with files *// Q& t, ~: R" `5 \
- fclose(inrbt_file);8 D& t% d a& l* l* t
- fclose(outrbt_file);
! A, V9 b: t5 P0 P - 2 e/ m: d6 q$ _6 Z+ M' N5 K/ I
- /* clean up subtitle library */' k2 X* M) A7 r& n
- ass_free_track(rbt.ass_track);
# K) d$ ~- I! U, T9 o- g$ D - ass_renderer_done(rbt.ass_renderer);
: a) R" \8 l/ v; f; l - ass_library_done(rbt.ass_lib);" {+ ?* r! ~+ w' q; D
- , t1 @2 f+ o( [( x% _9 O
- /* clean up */
) S V3 |9 ~- D/ W& d. u - free(rbt.frame_load_buffer);
6 K& B1 H) W$ y/ U- | - free(rbt.video_frame_size_table);7 W0 u: w+ s4 m0 x
- free(rbt.frame_size_table);5 w& s+ c+ K) C x$ a, ~
- % B9 Z% r+ i. P2 _" R
- return 0;
4 S5 f+ R1 H) i6 S! Z - }
复制代码 / K; b) k) ~1 Y0 L, A) w; m4 [0 g
6 I! \( g( h, t
7 S( m) f- l' u4 a" d
' w3 r0 V! l: N: k5 s/ C
|