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