r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / libmpeg3 / mpeg3cat.c
blob28023f7a05a6db56cde848180a4cb645ae670825
1 /* Concatenate elementary streams */
2 /* Mpeg3cat is useful for extracting elementary streams from program streams. */
5 #include "libmpeg3.h"
6 #include "mpeg3protos.h"
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
13 #define MPEG3_SEQUENCE_START_CODE 0x000001b3
14 #define BUFFER_SIZE 1000000
16 int main(int argc, char *argv[])
18 char inpath[1024], outpath[1024], newpath[1024];
19 mpeg3_t *in;
20 FILE *out;
21 int out_counter = 0;
22 int current_file, current_output_file = 0, i;
23 unsigned int bits;
24 unsigned char *buffer;
25 long output_size;
26 int result = 0;
27 long total_frames = 0;
28 int do_audio = 0, do_video = 0;
29 int stream = 0;
30 int64_t total_written = 0;
32 if(argc < 2)
34 fprintf(stderr, "Concatenate elementary streams or demultiplex a program stream.\n"
35 "Usage: mpeg3cat -[av0123456789] <infile> [infile...] > <outfile>\n\n"
36 "Example: Concatenate 2 video files: mpeg3cat xena1.m2v xena2.m2v > xena.m2v\n"
37 " Extract audio stream 0: mpeg3cat -a0 xena.vob > war_cry.ac3\n");
38 exit(1);
41 outpath[0] = 0;
42 for(i = 1; i < argc; i++)
44 if(argv[i][0] == '-')
46 if(argv[i][1] != 'a' && argv[i][1] != 'v' && argv[i][1] != 'o')
48 fprintf(stderr, "invalid option %s\n", argv[i]);
49 exit(1);
51 else
52 if(argv[i][1] == 'o')
54 // Check for filename
55 if(i < argc - 1)
57 strcpy(outpath, argv[++i]);
59 else
61 fprintf(stderr, "-o requires an output file\n");
62 exit(1);
65 // Check if file exists
66 if(out = fopen(outpath, "r"))
68 fprintf(stderr, "%s exists.\n", outpath);
69 exit(1);
73 else
75 if(argv[i][1] == 'a') do_audio = 1;
76 else
77 if(argv[i][1] == 'v') do_video = 1;
79 if(argv[i][2] != 0)
81 stream = argv[i][2] - 48;
87 buffer = malloc(BUFFER_SIZE);
88 if(outpath[0])
90 if(!(out = fopen(outpath, "wb")))
92 fprintf(stderr, "Failed to open %s for writing\n", outpath);
93 exit(1);
96 else
97 out = stdout;
99 for(current_file = 1; current_file < argc; current_file++)
101 if(argv[current_file][0] == '-') continue;
103 strcpy(inpath, argv[current_file]);
104 if(!(in = mpeg3_open(inpath)))
106 fprintf(stderr, "Skipping %s\n", inpath);
107 continue;
114 //fprintf(stderr, "%d %d %d %d\n", in->is_transport_stream, in->is_program_stream, in->is_audio_stream, in->is_video_stream);
115 if((mpeg3_has_audio(in) && in->is_audio_stream) ||
116 (do_audio && !in->is_audio_stream && !in->is_video_stream))
118 do_audio = 1;
119 /* Add audio stream to end */
120 mpeg3demux_seek_byte(in->atrack[stream]->demuxer, 0);
121 // mpeg3bits_refill(in->atrack[stream]->audio->astream);
122 while(!mpeg3_read_audio_chunk(in,
123 buffer,
124 &output_size,
125 BUFFER_SIZE,
126 stream))
128 result = !fwrite(buffer, output_size, 1, out);
129 if(result)
131 perror("fwrite audio chunk");
132 break;
136 else
137 if((mpeg3_has_video(in) && in->is_video_stream) ||
138 (do_video && !in->is_video_stream && !in->is_audio_stream))
140 /* Add video stream to end */
141 int hour, minute, second, frame;
142 long gop_frame;
143 unsigned long code;
144 float carry;
145 int i, offset;
147 mpeg3demux_seek_byte(in->vtrack[stream]->demuxer, 0);
148 mpeg3bits_refill(in->vtrack[stream]->video->vstream);
149 do_video = 1;
150 while(!mpeg3_read_video_chunk(in,
151 buffer,
152 &output_size,
153 BUFFER_SIZE,
154 stream) &&
155 output_size >= 4)
157 code = (unsigned long)buffer[output_size - 4] << 24;
158 code |= (unsigned long)buffer[output_size - 3] << 16;
159 code |= (unsigned long)buffer[output_size - 2] << 8;
160 code |= (unsigned long)buffer[output_size - 1];
162 /* Got a frame at the end of this buffer. */
163 if(code == MPEG3_PICTURE_START_CODE)
165 total_frames++;
167 else
168 if(code == MPEG3_SEQUENCE_END_CODE)
170 /* Got a sequence end code at the end of this buffer. */
171 output_size -= 4;
174 code = (unsigned long)buffer[0] << 24;
175 code |= (unsigned long)buffer[1] << 16;
176 code |= (unsigned long)buffer[2] << 8;
177 code |= buffer[3];
179 i = 0;
180 offset = 0;
181 if(code == MPEG3_SEQUENCE_START_CODE && current_output_file > 0)
183 /* Skip the sequence start code */
184 i += 4;
185 while(i < output_size &&
186 code != MPEG3_GOP_START_CODE)
188 code <<= 8;
189 code |= buffer[i++];
191 i -= 4;
192 offset = i;
195 /* Search for GOP header to fix */
196 code = (unsigned long)buffer[i++] << 24;
197 code |= (unsigned long)buffer[i++] << 16;
198 code |= (unsigned long)buffer[i++] << 8;
199 code |= buffer[i++];
200 while(i < output_size &&
201 code != MPEG3_GOP_START_CODE)
203 code <<= 8;
204 code |= buffer[i++];
207 if(code == MPEG3_GOP_START_CODE)
209 /* Get the time code */
210 code = (unsigned long)buffer[i] << 24;
211 code |= (unsigned long)buffer[i + 1] << 16;
212 code |= (unsigned long)buffer[i + 2] << 8;
213 code |= (unsigned long)buffer[i + 3];
215 hour = code >> 26 & 0x1f;
216 minute = code >> 20 & 0x3f;
217 second = code >> 13 & 0x3f;
218 frame = code >> 7 & 0x3f;
220 gop_frame = (long)(hour * 3600 * mpeg3_frame_rate(in, stream) +
221 minute * 60 * mpeg3_frame_rate(in, stream) +
222 second * mpeg3_frame_rate(in, stream) +
223 frame);
224 /* fprintf(stderr, "old: %02d:%02d:%02d:%02d ", hour, minute, second, frame); */
225 /* Write a new time code */
226 hour = (long)((float)(total_frames - 1) / mpeg3_frame_rate(in, stream) / 3600);
227 carry = hour * 3600 * mpeg3_frame_rate(in, stream);
228 minute = (long)((float)(total_frames - 1 - carry) / mpeg3_frame_rate(in, stream) / 60);
229 carry += minute * 60 * mpeg3_frame_rate(in, stream);
230 second = (long)((float)(total_frames - 1 - carry) / mpeg3_frame_rate(in, stream));
231 carry += second * mpeg3_frame_rate(in, stream);
232 frame = (total_frames - 1 - carry);
234 buffer[i] = ((code >> 24) & 0x80) | (hour << 2) | (minute >> 4);
235 buffer[i + 1] = ((code >> 16) & 0x08) | ((minute & 0xf) << 4) | (second >> 3);
236 buffer[i + 2] = ((second & 0x7) << 5) | (frame >> 1);
237 buffer[i + 3] = (code & 0x7f) | ((frame & 0x1) << 7);
238 /* fprintf(stderr, "new: %02d:%02d:%02d:%02d\n", hour, minute, second, frame); */
242 /* Test 32 bit overflow */
243 if(outpath[0])
245 if(ftell(out) > 0x7f000000)
247 fclose(out);
248 out_counter++;
249 sprintf(newpath, "%s%03d", outpath, out_counter);
250 if(!(out = fopen(newpath, "wb")))
252 fprintf(stderr, "Couldn't open %s for writing.\n", newpath);
253 exit(1);
258 * fprintf(stderr, "mpeg3cat 5 %02x %02x %02x %02x\n",
259 * (buffer + offset)[0],
260 * (buffer + offset)[1],
261 * (buffer + offset)[2],
262 * (buffer + offset)[3]);
265 /* Write the frame */
266 result = !fwrite(buffer + offset, output_size - offset, 1, out);
267 if(result)
269 perror("fwrite video chunk");
270 break;
274 else
275 if(in->is_program_stream)
277 mpeg3_demuxer_t *demuxer = in->vtrack[0]->demuxer;
278 result = 0;
279 //fprintf(stderr, "mpeg3cat 1\n");
281 /* Append program stream with no changes */
282 demuxer->read_all = 1;
283 mpeg3demux_seek_byte(demuxer, 0);
285 while(!result)
287 result = mpeg3_advance_timecode(demuxer, 0);
290 //fprintf(stderr, "mpeg3cat 1 %d\n", result);
291 if(!result)
293 result = mpeg3demux_read_program(demuxer);
294 if(result)
295 fprintf(stderr, "Hit end of data in %s\n", inpath);
299 // Decrypt it
300 if(!result)
302 long decryption_offset = demuxer->last_packet_decryption - demuxer->last_packet_start;
303 mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
304 mpeg3io_seek(title->fs, demuxer->last_packet_start);
305 demuxer->raw_size = demuxer->last_packet_end - demuxer->last_packet_start;
306 //fprintf(stderr, "mpeg3cat 2 %d %x\n", decryption_offset, demuxer->raw_data[decryption_offset]);
309 * if(demuxer->raw_size != 0x800)
310 * fprintf(stderr, __FUNCTION__ " %llx", demuxer->last_packet_start);
313 mpeg3io_read_data(demuxer->raw_data, demuxer->raw_size, title->fs);
314 if(decryption_offset > 0 &&
315 demuxer->raw_data[decryption_offset] & 0x30)
317 //fprintf(stderr, "mpeg3cat 3\n");
318 if(mpeg3_decrypt_packet(title->fs->css,
319 demuxer->raw_data,
322 fprintf(stderr, "get_ps_pes_packet: Decryption not available\n");
323 return 1;
325 //fprintf(stderr, "mpeg3cat 4\n");
326 demuxer->raw_data[decryption_offset] &= 0xcf;
330 //printf("mpeg3cat 3 %d\n", result);
331 // Write it
332 if(!result)
334 result = !fwrite(demuxer->raw_data,
335 demuxer->raw_size,
337 out);
338 total_written += demuxer->raw_size;
339 if(result) fprintf(stderr, "%s\n", strerror(errno));
342 //fprintf(stderr, "%llx %llx\n", mpeg3demux_tell(demuxer), mpeg3demux_tell(demuxer) - total_written);
345 else
347 fprintf(stderr, "Unsupported stream type.\n");
348 mpeg3_close(in);
349 in = 0;
350 continue;
353 mpeg3_close(in);
354 in = 0;
355 current_output_file++;
358 /* Terminate output */
359 if(current_output_file > 0 && do_video)
361 /*fprintf(stderr, "\n"); */
362 /* Write new end of sequence */
363 buffer[0] = MPEG3_SEQUENCE_END_CODE >> 24;
364 buffer[1] = (MPEG3_SEQUENCE_END_CODE >> 16) & 0xff;
365 buffer[2] = (MPEG3_SEQUENCE_END_CODE >> 8) & 0xff;
366 buffer[3] = MPEG3_SEQUENCE_END_CODE & 0xff;
367 result = !fwrite(buffer, 4, 1, out);
369 if(outpath[0]) fclose(out);
371 exit(0);