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