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