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