00001 #include <stdio.h>
00002 #include <stdlib.h>
00003
00004
00005 #include "libmpeg3.h"
00006 #include "mpeg3protos.h"
00007
00008 #define PACKET_SIZE 2048
00009
00010 typedef struct
00011 {
00012 int derivative;
00013 unsigned char packet_buffer[PACKET_SIZE];
00014 FILE *out_file;
00015 } multiplexer_t;
00016
00017 typedef struct
00018 {
00019 long bytes_decoded;
00020 long frames_decoded;
00021 long samples_decoded;
00022 mpeg3_t *file;
00023 FILE *raw_file;
00024 int stream_number;
00025 int end_of_data;
00026 } track_t;
00027
00028 int write_pack_header(unsigned char *ptr,
00029 multiplexer_t *mplex,
00030 float seconds,
00031 int stream_id,
00032 int ac3)
00033 {
00034 int packet_length;
00035
00036 *ptr++ = 0x00;
00037 *ptr++ = 0x00;
00038 *ptr++ = 0x01;
00039 *ptr++ = 0xba;
00040
00041 if(mplex->derivative == 1)
00042 {
00043 unsigned long timestamp = (unsigned long)(seconds * 90000);
00044 *ptr = 0x20;
00045 *ptr++ |= ((timestamp & 0xc0000000) >> 29) | 1;
00046 *ptr++ = (timestamp & 0x3fc00000) >> 22;
00047 *ptr++ = ((timestamp & 0x003f8000) >> 14) | 1;
00048 *ptr++ = (timestamp & 0x00007f80) >> 7;
00049 *ptr++ = ((timestamp & 0x0000007f) << 1) | 1;
00050
00051 *ptr++ = 0;
00052 *ptr++ = 0;
00053 *ptr++ = 0;
00054 }
00055 else
00056 if(mplex->derivative == 2)
00057 {
00058 *ptr = 0x40;
00059 }
00060
00061 *ptr++ = 0x00;
00062 *ptr++ = 0x00;
00063 *ptr++ = 0x01;
00064 if(ac3)
00065 *ptr++ = 0xbd;
00066 else
00067 *ptr++ = stream_id;
00068
00069
00070 packet_length = PACKET_SIZE - (ptr - mplex->packet_buffer) - 2;
00071 *ptr++ = (packet_length & 0xff00) >> 8;
00072 *ptr++ = packet_length & 0xff;
00073
00074
00075 *ptr++ = 0x0f;
00076
00077
00078 if(ac3)
00079 {
00080 *ptr++ = stream_id;
00081 *ptr++ = 0x00;
00082 *ptr++ = 0x00;
00083 *ptr++ = 0x00;
00084 }
00085
00086 return PACKET_SIZE - (ptr - mplex->packet_buffer);
00087 }
00088
00089 int write_packet(track_t *track,
00090 float start_time,
00091 float end_time,
00092 multiplexer_t *mplex,
00093 int stream_id,
00094 int ac3)
00095 {
00096 int result = 0;
00097
00098 long bytes_needed = track->bytes_decoded - ftell(track->raw_file);
00099 long current_byte = 0;
00100
00101 while(current_byte < bytes_needed)
00102 {
00103
00104 float current_time = start_time + (float)current_byte / bytes_needed * (end_time - start_time);
00105 int packet_bytes = write_pack_header(mplex->packet_buffer,
00106 mplex,
00107 current_time,
00108 stream_id,
00109 ac3);
00110 unsigned char *ptr = mplex->packet_buffer + PACKET_SIZE - packet_bytes;
00111 int bytes_read = fread(ptr, 1, packet_bytes, track->raw_file);
00112
00113 result = !fwrite(mplex->packet_buffer, PACKET_SIZE, 1, mplex->out_file);
00114 current_byte += packet_bytes;
00115 }
00116 return result;
00117 }
00118
00119 void skip_frame(mpeg3_demuxer_t *demuxer)
00120 {
00121 unsigned long header = 0;
00122 mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
00123
00124 do{
00125 header <<= 8;
00126 header &= 0xffffffff;
00127 header |= mpeg3io_read_char(title->fs);
00128 }while(header != MPEG3_PICTURE_START_CODE && !mpeg3io_eof(title->fs));
00129
00130
00131
00132
00133
00134 ((mpeg3_t*)demuxer->file)->last_type_read = 2;
00135 }
00136
00137 int main(int argc, char *argv[])
00138 {
00139 int streams = 0;
00140 int stream = 0;
00141 int result = 0;
00142 track_t *atracks[streams + 1];
00143 track_t *vtracks[streams + 1];
00144 int total_atracks = 0;
00145 int total_vtracks = 0;
00146 float frame_rate = 30000.0 / 1001.0;
00147 float sample_rate = 48000;
00148 long frames_decoded = 0;
00149 float *audio_temp = malloc(1);
00150 long audio_temp_allocated = 0;
00151 float current_time = 0, previous_time = 0;
00152 int video_completed = 0;
00153 int audio_completed = 0;
00154 int i;
00155 int ac3 = 0;
00156 multiplexer_t mplex;
00157 char **path;
00158 char *output_path;
00159 int old_percentage = 0;
00160
00161 path = malloc(sizeof(char*) * argc);
00162 mplex.derivative = 1;
00163 mplex.out_file = 0;
00164
00165 if(argc < 4)
00166 {
00167 printf("Tiny MPLEX by Heroine Virtual Ltd.\n");
00168 printf("Usage: mplex [-a] <stream 1> <stream2> ... <output>\n");
00169 printf(" -a use ac3 packet headers\n");
00170 exit(1);
00171 }
00172
00173 for(i = 1; i < argc; i++)
00174 {
00175 if(!strcmp(argv[i], "-a"))
00176 {
00177 ac3 = 1;
00178 }
00179 else
00180 if(i == argc - 1)
00181 {
00182 output_path = argv[i];
00183 }
00184 else
00185 {
00186 path[stream] = malloc(strlen(argv[i]) + 1);
00187 strcpy(path[stream], argv[i]);
00188 streams++;
00189 stream++;
00190 }
00191 }
00192
00193
00194 for(stream = 0; stream < streams; stream++)
00195 {
00196 int is_audio, is_video;
00197 int error_return;
00198 mpeg3_t *file = mpeg3_open(path[stream], &error_return);
00199
00200 if(!file)
00201 {
00202 printf("Couldn't open %s\n", path[stream]);
00203 result = 1;
00204 }
00205 else
00206 {
00207 is_audio = mpeg3_has_audio(file);
00208 is_video = mpeg3_has_video(file);
00209 mpeg3_set_cpus(file, 2);
00210
00211 if(is_audio && is_video)
00212 {
00213 printf("%s: Can't multiplex a system stream.\n", path[stream]);
00214 result = 1;
00215 }
00216 else
00217 if(is_audio)
00218 {
00219 atracks[total_atracks] = calloc(1, sizeof(track_t));
00220 atracks[total_atracks]->file = file;
00221 sample_rate = mpeg3_sample_rate(file, 0);
00222 atracks[total_atracks]->raw_file = fopen(path[stream], "rb");
00223 atracks[total_atracks]->stream_number = total_atracks;
00224 total_atracks++;
00225 }
00226 else
00227 if(is_video)
00228 {
00229 vtracks[total_vtracks] = calloc(1, sizeof(track_t));
00230 vtracks[total_vtracks]->file = file;
00231 frame_rate = mpeg3_frame_rate(file, 0);
00232 vtracks[total_vtracks]->raw_file = fopen(path[stream], "rb");
00233 vtracks[total_vtracks]->stream_number = total_vtracks;
00234
00235 skip_frame(vtracks[total_vtracks]->file->vtrack[0]->demuxer);
00236 total_vtracks++;
00237 }
00238 else
00239 {
00240 printf("%s: Has neither audio or video.\n", path[stream]);
00241 result = 1;
00242 }
00243 }
00244 }
00245
00246 if(!result)
00247 {
00248 if(!total_vtracks)
00249 {
00250 printf("You must supply at least 1 video track.\n");
00251 result = 1;
00252 }
00253 }
00254
00255
00256 if(!result)
00257 if(!(mplex.out_file = fopen(output_path, "wb")))
00258 {
00259 printf("Couldn't open output file\n");
00260 result = 1;
00261 }
00262
00263
00264 if(!result)
00265 {
00266 while(!result && !(video_completed && audio_completed))
00267 {
00268 previous_time = current_time;
00269
00270 for(stream = 0; stream < total_vtracks && !result; stream++)
00271 {
00272
00273 track_t *track = vtracks[stream];
00274
00275 if(!track->end_of_data)
00276 {
00277 int percentage;
00278 skip_frame(track->file->vtrack[0]->demuxer);
00279 track->frames_decoded++;
00280 track->bytes_decoded = mpeg3demux_tell_byte(
00281 track->file->vtrack[0]->demuxer);
00282 if(track->frames_decoded > frames_decoded)
00283 {
00284 frames_decoded = track->frames_decoded;
00285 current_time = (float)frames_decoded / frame_rate;
00286 }
00287
00288 result = write_packet(track,
00289 previous_time,
00290 current_time,
00291 &mplex,
00292 0xe0 | track->stream_number,
00293 0);
00294 track->end_of_data = mpeg3_end_of_video(track->file, 0);
00295 percentage = (int)(mpeg3demux_tell_byte(track->file->vtrack[0]->demuxer) *
00296 100 /
00297 mpeg3demux_movie_size(track->file->vtrack[0]->demuxer));
00298 if(percentage - old_percentage >= 1)
00299 {
00300 printf("\t%d%% completed\r", percentage);
00301 old_percentage = percentage;
00302 }
00303 fflush(stdout);
00304 }
00305 }
00306
00307
00308 for(stream = 0; stream < total_atracks && !result; stream++)
00309 {
00310 track_t *track = atracks[stream];
00311
00312 if(!track->end_of_data &&
00313 (track->samples_decoded < current_time * sample_rate ||
00314 video_completed))
00315 {
00316 if(!video_completed)
00317 {
00318 long samples_needed = (long)(current_time * sample_rate) - track->samples_decoded;
00319 if(audio_temp_allocated < samples_needed)
00320 {
00321 free(audio_temp);
00322 audio_temp = malloc(sizeof(float) * samples_needed);
00323 audio_temp_allocated = samples_needed;
00324 }
00325
00326 mpeg3_read_audio(track->file,
00327 audio_temp,
00328 0,
00329 0,
00330 samples_needed,
00331 0);
00332 track->bytes_decoded = mpeg3demux_tell_byte(track->file->atrack[0]->demuxer);
00333 if(!track->end_of_data) track->bytes_decoded -= 2048;
00334 track->samples_decoded += samples_needed;
00335 track->end_of_data = mpeg3_end_of_audio(track->file, 0);
00336 }
00337 else
00338 {
00339 track->bytes_decoded = mpeg3demux_movie_size(track->file->atrack[0]->demuxer);
00340 track->end_of_data = 1;
00341 }
00342
00343
00344 result = write_packet(track,
00345 previous_time,
00346 current_time,
00347 &mplex,
00348 ac3 ? track->stream_number : (0xc0 | track->stream_number),
00349 ac3);
00350 }
00351 }
00352
00353 for(stream = 0; stream < total_vtracks; stream++)
00354 {
00355 if(vtracks[stream]->end_of_data) video_completed++;
00356 }
00357 if(video_completed < total_vtracks) video_completed = 0;
00358
00359 for(stream = 0; stream < total_atracks; stream++)
00360 {
00361 if(atracks[stream]->end_of_data) audio_completed++;
00362 }
00363 if(audio_completed < total_atracks) audio_completed = 0;
00364 }
00365 }
00366
00367
00368 for(stream = 0; stream < total_atracks; stream++)
00369 {
00370 mpeg3_close(atracks[stream]->file);
00371 fclose(atracks[stream]->raw_file);
00372 free(atracks[stream]);
00373 }
00374
00375 for(stream = 0; stream < total_vtracks; stream++)
00376 {
00377 mpeg3_close(vtracks[stream]->file);
00378 fclose(vtracks[stream]->raw_file);
00379 free(vtracks[stream]);
00380 }
00381
00382 if(mplex.out_file) fclose(mplex.out_file);
00383
00384 return result;
00385 }
00386
00387