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