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