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