00001
00002
00003
00004
00005 #include "libmpeg3.h"
00006 #include "mpeg3protos.h"
00007
00008 #include <errno.h>
00009 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012
00013 #define MPEG3_SEQUENCE_START_CODE 0x000001b3
00014 #define BUFFER_SIZE 1000000
00015
00016 int main(int argc, char *argv[])
00017 {
00018 char inpath[1024], outpath[1024], newpath[1024];
00019 char *inpaths[argc];
00020 int total_infiles = 0;
00021 mpeg3_t *in;
00022 FILE *out;
00023 int out_counter = 0;
00024 int current_file, current_output_file = 0, i;
00025 unsigned int bits;
00026 unsigned char *buffer;
00027 long output_size;
00028 int result = 0;
00029 long total_frames = 0;
00030 int do_audio = 0, do_video = 0;
00031 int stream = 0;
00032 int64_t total_written = 0;
00033
00034 if(argc < 2)
00035 {
00036 fprintf(stderr, "Concatenate elementary streams or demultiplex a program stream.\n"
00037 "Usage: mpeg3cat -[av0123456789] <infile> [infile...] > <outfile>\n\n"
00038 "Example: Concatenate 2 video files: mpeg3cat xena1.m2v xena2.m2v > xena.m2v\n"
00039 " Extract audio stream 0: mpeg3cat -a0 xena.vob > war_cry.ac3\n");
00040 exit(1);
00041 }
00042
00043 outpath[0] = 0;
00044 for(i = 1; i < argc; i++)
00045 {
00046 if(argv[i][0] == '-')
00047 {
00048 if(argv[i][1] != 'a' && argv[i][1] != 'v' && argv[i][1] != 'o')
00049 {
00050 fprintf(stderr, "invalid option %s\n", argv[i]);
00051 exit(1);
00052 }
00053 else
00054 if(argv[i][1] == 'o')
00055 {
00056
00057 if(i < argc - 1)
00058 {
00059 strcpy(outpath, argv[++i]);
00060 }
00061 else
00062 {
00063 fprintf(stderr, "-o requires an output file\n");
00064 exit(1);
00065 }
00066
00067
00068 if(out = fopen(outpath, "r"))
00069 {
00070 fprintf(stderr, "%s exists.\n", outpath);
00071 exit(1);
00072 }
00073
00074 }
00075 else
00076 {
00077 if(argv[i][1] == 'a') do_audio = 1;
00078 else
00079 if(argv[i][1] == 'v') do_video = 1;
00080
00081 if(argv[i][2] != 0)
00082 {
00083 stream = argv[i][2] - '0';
00084 }
00085 }
00086 }
00087 else
00088 {
00089 inpaths[total_infiles++] = argv[i];
00090 }
00091 }
00092
00093 buffer = malloc(BUFFER_SIZE);
00094 if(outpath[0])
00095 {
00096 if(!(out = fopen(outpath, "wb")))
00097 {
00098 fprintf(stderr, "Failed to open %s for writing\n", outpath);
00099 exit(1);
00100 }
00101 }
00102 else
00103 out = stdout;
00104
00105 for(current_file = 0; current_file < total_infiles; current_file++)
00106 {
00107 strcpy(inpath, inpaths[current_file]);
00108
00109 int error = 0;
00110 if(!(in = mpeg3_open(inpath, &error)))
00111 {
00112 fprintf(stderr, "Skipping %s\n", inpath);
00113 continue;
00114 }
00115
00116
00117
00118
00119
00120
00121 if((mpeg3_has_audio(in) && in->is_audio_stream) ||
00122 (do_audio && !in->is_audio_stream && !in->is_video_stream))
00123 {
00124 do_audio = 1;
00125
00126 if(stream >= in->total_astreams)
00127 {
00128 fprintf(stderr, "No audio stream %d\n", stream);
00129 exit(1);
00130 }
00131
00132 mpeg3demux_seek_byte(in->atrack[stream]->demuxer, 0);
00133
00134
00135 while(!mpeg3_read_audio_chunk(in,
00136 buffer,
00137 &output_size,
00138 BUFFER_SIZE,
00139 stream))
00140 {
00141
00142 result = !fwrite(buffer, output_size, 1, out);
00143 if(result)
00144 {
00145 perror("fwrite audio chunk");
00146 break;
00147 }
00148 }
00149
00150 }
00151 else
00152
00153 if((mpeg3_has_video(in) && in->is_video_stream) ||
00154 (do_video && !in->is_video_stream && !in->is_audio_stream))
00155 {
00156
00157 int hour, minute, second, frame;
00158 long gop_frame;
00159 unsigned long code;
00160 float carry;
00161 int i, offset;
00162
00163 if(stream >= in->total_vstreams)
00164 {
00165 fprintf(stderr, "No audio stream %d\n", stream);
00166 exit(1);
00167 }
00168
00169 mpeg3demux_seek_byte(in->vtrack[stream]->demuxer, 0);
00170 mpeg3bits_refill(in->vtrack[stream]->video->vstream);
00171 do_video = 1;
00172 while(!mpeg3_read_video_chunk(in,
00173 buffer,
00174 &output_size,
00175 BUFFER_SIZE,
00176 stream) &&
00177 output_size >= 4)
00178 {
00179 code = (unsigned long)buffer[output_size - 4] << 24;
00180 code |= (unsigned long)buffer[output_size - 3] << 16;
00181 code |= (unsigned long)buffer[output_size - 2] << 8;
00182 code |= (unsigned long)buffer[output_size - 1];
00183
00184
00185 if(code == MPEG3_PICTURE_START_CODE)
00186 {
00187 total_frames++;
00188 }
00189 else
00190 if(code == MPEG3_SEQUENCE_END_CODE)
00191 {
00192
00193 output_size -= 4;
00194 }
00195
00196 code = (unsigned long)buffer[0] << 24;
00197 code |= (unsigned long)buffer[1] << 16;
00198 code |= (unsigned long)buffer[2] << 8;
00199 code |= buffer[3];
00200
00201 i = 0;
00202 offset = 0;
00203 if(code == MPEG3_SEQUENCE_START_CODE && current_output_file > 0)
00204 {
00205
00206 i += 4;
00207 while(i < output_size &&
00208 code != MPEG3_GOP_START_CODE)
00209 {
00210 code <<= 8;
00211 code |= buffer[i++];
00212 }
00213 i -= 4;
00214 offset = i;
00215 }
00216
00217
00218 code = (unsigned long)buffer[i++] << 24;
00219 code |= (unsigned long)buffer[i++] << 16;
00220 code |= (unsigned long)buffer[i++] << 8;
00221 code |= buffer[i++];
00222 while(i < output_size &&
00223 code != MPEG3_GOP_START_CODE)
00224 {
00225 code <<= 8;
00226 code |= buffer[i++];
00227 }
00228
00229 if(code == MPEG3_GOP_START_CODE)
00230 {
00231
00232 code = (unsigned long)buffer[i] << 24;
00233 code |= (unsigned long)buffer[i + 1] << 16;
00234 code |= (unsigned long)buffer[i + 2] << 8;
00235 code |= (unsigned long)buffer[i + 3];
00236
00237 hour = code >> 26 & 0x1f;
00238 minute = code >> 20 & 0x3f;
00239 second = code >> 13 & 0x3f;
00240 frame = code >> 7 & 0x3f;
00241
00242 gop_frame = (long)(hour * 3600 * mpeg3_frame_rate(in, stream) +
00243 minute * 60 * mpeg3_frame_rate(in, stream) +
00244 second * mpeg3_frame_rate(in, stream) +
00245 frame);
00246
00247
00248 hour = (long)((float)(total_frames - 1) / mpeg3_frame_rate(in, stream) / 3600);
00249 carry = hour * 3600 * mpeg3_frame_rate(in, stream);
00250 minute = (long)((float)(total_frames - 1 - carry) / mpeg3_frame_rate(in, stream) / 60);
00251 carry += minute * 60 * mpeg3_frame_rate(in, stream);
00252 second = (long)((float)(total_frames - 1 - carry) / mpeg3_frame_rate(in, stream));
00253 carry += second * mpeg3_frame_rate(in, stream);
00254 frame = (total_frames - 1 - carry);
00255
00256 buffer[i] = ((code >> 24) & 0x80) | (hour << 2) | (minute >> 4);
00257 buffer[i + 1] = ((code >> 16) & 0x08) | ((minute & 0xf) << 4) | (second >> 3);
00258 buffer[i + 2] = ((second & 0x7) << 5) | (frame >> 1);
00259 buffer[i + 3] = (code & 0x7f) | ((frame & 0x1) << 7);
00260
00261 }
00262
00263
00264
00265 if(outpath[0])
00266 {
00267 if(ftell(out) > 0x7f000000)
00268 {
00269 fclose(out);
00270 out_counter++;
00271 sprintf(newpath, "%s%03d", outpath, out_counter);
00272 if(!(out = fopen(newpath, "wb")))
00273 {
00274 fprintf(stderr, "Couldn't open %s for writing.\n", newpath);
00275 exit(1);
00276 }
00277 }
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 result = !fwrite(buffer + offset, output_size - offset, 1, out);
00289 if(result)
00290 {
00291 perror("fwrite video chunk");
00292 break;
00293 }
00294 }
00295 }
00296 else
00297
00298 if(in->is_program_stream)
00299 {
00300 mpeg3_demuxer_t *demuxer = in->vtrack[0]->demuxer;
00301 result = 0;
00302
00303
00304 demuxer->read_all = 1;
00305 mpeg3demux_seek_byte(demuxer, 0);
00306
00307
00308
00309 while(!result)
00310 {
00311 result = mpeg3_seek_phys(demuxer);
00312
00313
00314 if(!result)
00315 {
00316 demuxer->data_size = 0;
00317 demuxer->video_size = 0;
00318 demuxer->audio_size = 0;
00319 result = mpeg3demux_read_program(demuxer);
00320 if(result)
00321 fprintf(stderr, "Hit end of data in %s\n", inpath);
00322 }
00323
00324
00325
00326 unsigned char *raw_data = malloc(0x10000);
00327 int raw_size = 0;
00328 if(!result)
00329 {
00330 mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
00331 int64_t temp_offset = mpeg3io_tell(title->fs);
00332 int64_t decryption_offset = demuxer->last_packet_decryption - demuxer->last_packet_start;
00333 raw_size = demuxer->last_packet_end - demuxer->last_packet_start;
00334
00335 mpeg3io_seek(title->fs, demuxer->last_packet_start);
00336 mpeg3io_read_data(raw_data, raw_size, title->fs);
00337 mpeg3io_seek(title->fs, temp_offset);
00338
00339
00340 if(decryption_offset > 0 &&
00341 decryption_offset < raw_size &&
00342 raw_data[decryption_offset] & 0x30)
00343 {
00344 if(mpeg3_decrypt_packet(title->fs->css,
00345 raw_data,
00346 0))
00347 {
00348 fprintf(stderr, "get_ps_pes_packet: Decryption not available\n");
00349 return 1;
00350 }
00351 raw_data[decryption_offset] &= 0xcf;
00352 }
00353 }
00354
00355
00356 if(!result)
00357 {
00358 result = !fwrite(raw_data,
00359 raw_size,
00360 1,
00361 out);
00362 total_written += raw_size;
00363 if(result) fprintf(stderr, "%s\n", strerror(errno));
00364 }
00365
00366 free(raw_data);
00367 }
00368 }
00369 else
00370
00371 {
00372 fprintf(stderr, "Unsupported stream type.\n");
00373 mpeg3_close(in);
00374 in = 0;
00375 continue;
00376 }
00377
00378 mpeg3_close(in);
00379 in = 0;
00380 current_output_file++;
00381 }
00382
00383
00384 if(current_output_file > 0 && do_video)
00385 {
00386
00387
00388 buffer[0] = MPEG3_SEQUENCE_END_CODE >> 24;
00389 buffer[1] = (MPEG3_SEQUENCE_END_CODE >> 16) & 0xff;
00390 buffer[2] = (MPEG3_SEQUENCE_END_CODE >> 8) & 0xff;
00391 buffer[3] = MPEG3_SEQUENCE_END_CODE & 0xff;
00392 result = !fwrite(buffer, 4, 1, out);
00393 }
00394 if(outpath[0]) fclose(out);
00395
00396 exit(0);
00397 }