1 /*******************************************************************************
2 recover.c
3
4 libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5 http://libquicktime.sourceforge.net
6
7 Copyright (C) 2002 Heroine Virtual Ltd.
8 Copyright (C) 2002-2011 Members of the libquicktime project.
9
10 This library is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free
12 Software Foundation; either version 2.1 of the License, or (at your option)
13 any later version.
14
15 This library is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along
21 with this library; if not, write to the Free Software Foundation, Inc., 51
22 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *******************************************************************************/
24
25 #include "lqt_private.h"
26 #include "lqt_fseek.h"
27 /*#include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <inttypes.h>*/
32
33 #define WIDTH 720
34 #define HEIGHT 480
35 #define FRAMERATE (float)30000/1001
36 #define CHANNELS 2
37 #define SAMPLERATE 96000
38 #define BITS 24
39 #define TEMP_FILE "/tmp/temp.mov"
40
41
42
43
44
45
46 #define SEARCH_FRAGMENT (int64_t)0x1000
47
usage()48 void usage()
49 {
50 printf("Recover JPEG and PCM audio in a corrupted movie.\n"
51 "Usage: recover [-w width] [-h height] [-f framerate]\n"
52 "\t[-c audiochannels] [-r samplerate] [-b audiobits] [-t tempfile] <input>\n"
53 "Compiled in defaults:\n"
54 " WIDTH %d\n"
55 " HEIGHT %d\n"
56 " FRAMERATE %.2f\n"
57 " CHANNELS %d\n"
58 " SAMPLERATE %d\n"
59 " BITS %d\n"
60 " TEMP_FILE %s\n",
61 WIDTH, HEIGHT,
62 FRAMERATE,
63 CHANNELS,
64 SAMPLERATE,
65 BITS,
66 TEMP_FILE
67 );
68
69 exit( -1 );
70 }
71
main(int argc,char * argv[])72 int main(int argc, char *argv[])
73 {
74 FILE *in;
75 FILE *temp;
76 quicktime_t *out;
77 int64_t current_byte, ftell_byte;
78 int64_t jpeg_start = 0, jpeg_end = 0;
79 int64_t audio_start, audio_end = 0;
80 unsigned char *search_buffer = calloc(1, SEARCH_FRAGMENT);
81 unsigned char *copy_buffer = 0;
82 int i, found_jfif, found_eoi;
83 int64_t file_size;
84 struct stat status;
85 unsigned char data[8];
86 struct stat ostat;
87
88 long width = WIDTH, height = HEIGHT;
89 float frame_rate = FRAMERATE;
90 int channels = CHANNELS, sample_rate = SAMPLERATE, bits = BITS;
91 char *temp_file = TEMP_FILE;
92 char *input_file = NULL;
93 int have_input = 0;
94
95 if(argc < 2)
96 {
97 printf("Recover JPEG and PCM audio in a corrupted movie.\n"
98 "Usage: recover [-w width] [-h height] [-f framerate]\n"
99 "\t[-c audiochannels] [-r samplerate] [-b audiobits] <input> [<output>]\n"
100 "Compiled in defaults:\n"
101 " WIDTH %ld\n"
102 " HEIGHT %ld\n"
103 " FRAMERATE %.2f\n"
104 " CHANNELS %d\n"
105 " SAMPLERATE %d\n"
106 " BITS %d\n"
107 " TEMP_FILE %s\n",
108 width, height,
109 frame_rate,
110 channels,
111 sample_rate,
112 bits,
113 temp_file);
114 exit(1);
115 }
116
117 for(i = 1; i < argc; i++)
118 {
119 if(!strcmp(argv[i], "-f"))
120 {
121 if(i + 1 < argc)
122 {
123 frame_rate = atof(argv[++i]);
124 }
125 else
126 usage();
127 }
128 else
129 if(!strcmp(argv[i], "-w"))
130 {
131 if(i + 1 < argc)
132 width = atol(argv[++i]);
133 else
134 usage();
135 }
136 else
137 if(!strcmp(argv[i], "-h"))
138 {
139 if(i + 1 < argc)
140 height = atol(argv[++i]);
141 else
142 usage();
143 }
144 else
145 if(!strcmp(argv[i], "-r"))
146 {
147 if(i + 1 < argc)
148 sample_rate = atol(argv[++i]);
149 else
150 usage();
151 }
152 else
153 if(!strcmp(argv[i], "-c"))
154 {
155 if(i + 1 < argc)
156 channels = atol(argv[++i]);
157 else
158 usage();
159 }
160 else
161 if(!strcmp(argv[i], "-b"))
162 {
163 if(i + 1 < argc)
164 bits = atol(argv[++i]);
165 else
166 usage();
167 }
168 else
169 if(!strcmp(argv[i], "-t"))
170 {
171 if(i + 1 < argc)
172 temp_file = argv[++i];
173 else
174 usage();
175 }
176 else if( ! have_input )
177 {
178 input_file = argv[i];
179 have_input = 1;
180 }
181 else
182 {
183 usage();
184 }
185 }
186
187 printf( "Using options:\n"
188 " WIDTH %ld\n"
189 " HEIGHT %ld\n"
190 " FRAMERATE %.2f\n"
191 " CHANNELS %d\n"
192 " SAMPLERATE %d\n"
193 " BITS %d\n"
194 " INPUT %s\n"
195 " TEMP_FILE %s\n",
196 width, height,
197 frame_rate,
198 channels,
199 sample_rate,
200 bits,
201 input_file,
202 temp_file);
203
204
205 in = fopen(input_file, "rb+");
206 out = quicktime_open(temp_file, 0, 1);
207
208 if(!in)
209 {
210 perror("open input");
211 exit(1);
212 }
213 if(!out)
214 {
215 perror("open temp");
216 exit(1);
217 }
218
219 quicktime_set_audio(out,
220 channels,
221 sample_rate,
222 bits,
223 QUICKTIME_TWOS);
224 quicktime_set_video(out,
225 1,
226 width, height,
227 frame_rate,
228 QUICKTIME_JPEG);
229 audio_start = (int64_t)0x10;
230 found_jfif = 0;
231 found_eoi = 0;
232 ftell_byte = 0;
233
234 if(fstat(fileno(in), &status))
235 perror("get_file_length fstat:");
236 file_size = status.st_size;
237
238
239 //printf("recover %lld\n", file_size);
240 while(ftell_byte < file_size)
241 {
242 // Search forward for JFIF
243 current_byte = ftell_byte;
244 fread(search_buffer, SEARCH_FRAGMENT, 1, in);
245 ftell_byte += SEARCH_FRAGMENT;
246 for(i = 0; i < SEARCH_FRAGMENT - 4; i++)
247 {
248 if(!found_jfif)
249 {
250 if(search_buffer[i] == 'J' &&
251 search_buffer[i + 1] == 'F' &&
252 search_buffer[i + 2] == 'I' &&
253 search_buffer[i + 3] == 'F')
254 {
255 current_byte += i - 6;
256 fseeko(in, current_byte, SEEK_SET);
257 ftell_byte = current_byte;
258 found_jfif = 1;
259 audio_end = jpeg_start = current_byte;
260 break;
261 }
262 }
263 else
264 if(!found_eoi)
265 {
266 if(search_buffer[i] == 0xff &&
267 search_buffer[i + 1] == 0xd9)
268 {
269 current_byte += i + 2;
270 fseeko(in, current_byte, SEEK_SET);
271 ftell_byte = current_byte;
272 found_eoi = 1;
273 audio_start = jpeg_end = current_byte;
274 break;
275 }
276 }
277 }
278
279 // Write audio chunk
280 if(found_jfif && !found_eoi && audio_end - audio_start > 0)
281 {
282 long samples = (audio_end - audio_start) / (channels * bits / 8);
283 quicktime_update_tables(out,
284 out->atracks[0].track,
285 audio_start,
286 out->atracks[0].current_chunk,
287 out->atracks[0].current_position,
288 samples,
289 0);
290 out->atracks[0].current_position += samples;
291 out->atracks[0].current_chunk++;
292 printf("got audio %llx - %llx = %llx\r", audio_end, audio_start, audio_end - audio_start);
293 fflush(stdout);
294 audio_start = audio_end;
295 }
296 else
297 // Write video chunk
298 if(found_jfif && found_eoi)
299 {
300 quicktime_update_tables(out,
301 out->vtracks[0].track,
302 jpeg_start,
303 out->vtracks[0].current_chunk,
304 out->vtracks[0].current_position,
305 1,
306 jpeg_end - jpeg_start);
307 out->vtracks[0].current_position++;
308 out->vtracks[0].current_chunk++;
309 found_jfif = 0;
310 found_eoi = 0;
311 }
312 else
313 {
314 fseeko(in, current_byte + SEARCH_FRAGMENT - 4, SEEK_SET);
315 ftell_byte = current_byte + SEARCH_FRAGMENT - 4;
316 }
317 }
318 printf("\n\n");
319 // Force header out
320 quicktime_close(out);
321
322 // Transfer header
323 fseeko(in, 0x8, SEEK_SET);
324
325 data[0] = (ftell_byte & 0xff00000000000000LL) >> 56;
326 data[1] = (ftell_byte & 0xff000000000000LL) >> 48;
327 data[2] = (ftell_byte & 0xff0000000000LL) >> 40;
328 data[3] = (ftell_byte & 0xff00000000LL) >> 32;
329 data[4] = (ftell_byte & 0xff000000LL) >> 24;
330 data[5] = (ftell_byte & 0xff0000LL) >> 16;
331 data[6] = (ftell_byte & 0xff00LL) >> 8;
332 data[7] = ftell_byte & 0xff;
333 fwrite(data, 8, 1, in);
334
335 fseeko(in, ftell_byte, SEEK_SET);
336 stat(temp_file, &ostat);
337 temp = fopen(temp_file, "rb");
338 fseeko(temp, 0x10, SEEK_SET);
339 copy_buffer = calloc(1, ostat.st_size);
340 fread(copy_buffer, ostat.st_size, 1, temp);
341 fclose(temp);
342 fwrite(copy_buffer, ostat.st_size, 1, in);
343
344 fclose(in);
345 exit (EXIT_SUCCESS);
346 }
347
348
349
350
351