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