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