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