Initial import of MPlayer SVN rev 28382 and FFmpeg SVN rev 16846.
[vaapi:miks-mplayer.git] / TOOLS / subrip.c
1 /*
2  * Use with CVS JOCR/GOCR.
3  *
4  * You will have to change 'vobsub_id' value if you want another subtitle than number 0.
5  *
6  * HINT: you can view the subtitle that is being decoded with "display subtitle-*.pgm"
7  *
8  */
9
10 /* Make sure this accesses the CVS version of JOCR/GOCR */
11 #define GOCR_PROGRAM "gocr"
12
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include "libvo/video_out.h"
21 #include "vobsub.h"
22 #include "spudec.h"
23
24 void guiMessageBox(int level, char * str) {};
25
26 /* XXX Kludge ahead, this MUST be the same as the definitions found in ../spudec.c */
27 typedef struct packet_t packet_t;
28 struct packet_t {
29   unsigned char *packet;
30   unsigned int palette[4];
31   unsigned int alpha[4];
32   unsigned int control_start;   /* index of start of control data */
33   unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
34                                      processed (for RLE decoding) for
35                                      even and odd lines */
36   int deinterlace_oddness;      /* 0 or 1, index into current_nibble */
37   unsigned int start_col, end_col;
38   unsigned int start_row, end_row;
39   unsigned int width, height, stride;
40   unsigned int start_pts, end_pts;
41   packet_t *next;
42 };
43 typedef struct {
44   packet_t *queue_head;
45   packet_t *queue_tail;
46   unsigned int global_palette[16];
47   unsigned int orig_frame_width, orig_frame_height;
48   unsigned char* packet;
49   size_t packet_reserve;        /* size of the memory pointed to by packet */
50   unsigned int packet_offset;   /* end of the currently assembled fragment */
51   unsigned int packet_size;     /* size of the packet once all fragments are assembled */
52   unsigned int packet_pts;      /* PTS for this packet */
53   unsigned int palette[4];
54   unsigned int alpha[4];
55   unsigned int cuspal[4];
56   unsigned int custom;
57   unsigned int now_pts;
58   unsigned int start_pts, end_pts;
59   unsigned int start_col, end_col;
60   unsigned int start_row, end_row;
61   unsigned int width, height, stride;
62   size_t image_size;            /* Size of the image buffer */
63   unsigned char *image;         /* Grayscale value */
64   unsigned char *aimage;        /* Alpha value */
65   unsigned int scaled_frame_width, scaled_frame_height;
66   unsigned int scaled_start_col, scaled_start_row;
67   unsigned int scaled_width, scaled_height, scaled_stride;
68   size_t scaled_image_size;
69   unsigned char *scaled_image;
70   unsigned char *scaled_aimage;
71   int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
72   int font_start_level;  /* Darkest value used for the computed font */
73   const vo_functions_t *hw_spu;
74   int spu_changed;
75 } spudec_handle_t;
76
77 int use_gui;
78 int gtkMessageBox;
79 int identify=0;
80 int vobsub_id=0;
81 int sub_pos=0;
82
83 static spudec_handle_t *spudec;
84 static FILE *fsub = NULL;
85 static unsigned int sub_idx = 0;
86
87 static void
88 process_gocr_output(const char *const fname, unsigned int start, unsigned int end)
89 {
90     FILE *file;
91     int temp, h, m, s, ms;
92     int c, bol;
93     file = fopen(fname, "r");
94     if (file == NULL) {
95         perror("fopen failed");
96         return;
97     }
98     temp = start;
99     temp /= 90;
100     h = temp / 3600000;
101     temp %= 3600000;
102     m = temp / 60000;
103     temp %= 60000;
104     s = temp / 1000;
105     temp %= 1000;
106     ms = temp;
107     fprintf(fsub, "%d\n%02d:%02d:%02d,%03d --> ", ++sub_idx, h, m, s, ms);
108     temp = end;
109     temp /= 90;
110     h = temp / 3600000;
111     temp %= 3600000;
112     m = temp / 60000;
113     temp %= 60000;
114     s = temp / 1000;
115     temp %= 1000;
116     ms = temp;
117     fprintf(fsub, "%02d:%02d:%02d,%03d\n", h, m, s, ms);
118     bol = 1;
119     while ((c = getc(file)) != EOF) {
120         if (bol) {
121             if (!isspace(c)) {
122                 putc(c, fsub);
123                 bol=0;
124             }
125         }
126         else if (!bol) {
127             putc(c, fsub);
128             bol = c == '\n';
129         }
130     }
131     putc('\n', fsub);
132     fflush(fsub);
133     fclose(file);
134 }
135
136 static void
137 output_pgm(FILE *f, int w, int h, unsigned char *src, unsigned char *srca, int stride)
138 {
139     int x, y;
140     fprintf(f,
141             "P5\n"
142             "%d %d\n"
143             "255\n",
144             w, h);
145     for (y = 0; y < h; ++y) {
146         for (x = 0; x < w; ++x) {
147             int res;
148             if (srca[x])
149                 res = src[x] * (256 - srca[x]);
150             else
151                 res = 0;
152             res = (65535 - res) >> 8;
153             putc(res&0xff, f);
154
155         }
156         src += stride;
157         srca += stride;
158     }
159     putc('\n', f);
160 }
161
162 static void
163 draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
164 {
165     FILE *f;
166     char buf[128];
167     char cmd[512];
168     int cmdres;
169     const char *const tmpfname = tmpnam(NULL);
170     sprintf(buf, "subtitle-%d-%d.pgm", spudec->start_pts / 90, spudec->end_pts / 90);
171     f = fopen(buf, "w");
172     output_pgm(f, w, h, src, srca, stride);
173     fclose(f);
174     /* see <URL:http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/subtitleripper/subtitleripper/src/README.gocr?rev=HEAD&content-type=text/vnd.viewcvs-markup> */
175     sprintf(cmd, GOCR_PROGRAM" -v 1 -s 7 -d 0 -m 130 -m 256 -m 32 -i %s -o %s", buf, tmpfname);
176     cmdres = system(cmd);
177     if (cmdres < 0) {
178         perror("system failed");
179         exit(EXIT_FAILURE);
180     }
181     else if (cmdres) {
182         fprintf(stderr, GOCR_PROGRAM" returned %d\n", cmdres);
183         exit(cmdres);
184     }
185     process_gocr_output(tmpfname, spudec->start_pts, spudec->end_pts);
186     unlink(buf);
187     unlink(tmpfname);
188 }
189
190 int
191 main(int argc, char **argv)
192 {
193     const char *vobsubname, *subripname;
194     void *vobsub;
195     void *packet;
196     int packet_len;
197     unsigned int pts100;
198
199     if (argc < 2 || 4 < argc) {
200         fprintf(stderr, "Usage: %s <vobsub basename> [<subid> [<output filename>] ]\n", argv[0]);
201         exit(EXIT_FAILURE);
202     }
203     vobsubname = argv[1];
204     subripname = NULL;
205     fsub = stdout;
206     if (argc >= 3)
207         vobsub_id = atoi(argv[2]);
208     if (argc >= 4) {
209         subripname = argv[3];
210         fsub = fopen(subripname, "w");
211     }
212
213     vobsub = vobsub_open(vobsubname, NULL, 0, &spudec);
214     while ((packet_len=vobsub_get_next_packet(vobsub, &packet, &pts100)) >= 0) {
215         spudec_assemble(spudec, packet, packet_len, pts100);
216         if (spudec->queue_head) {
217                 spudec_heartbeat(spudec, spudec->queue_head->start_pts);
218         if (spudec_changed(spudec)) 
219             spudec_draw(spudec, draw_alpha);
220         }
221     }
222
223     if (vobsub)
224         vobsub_close(vobsub);
225     exit(EXIT_SUCCESS);
226 }