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