Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / mplexlo / mplex.c
blob8fc95f330356733ef4a3516cd27d106bb18f33bb
1 #include <stdio.h>
2 #include <stdlib.h>
5 #include "libmpeg3.h"
6 #include "mpeg3protos.h"
8 #define PACKET_SIZE 2048
10 typedef struct
12 int derivative;
13 unsigned char packet_buffer[PACKET_SIZE];
14 FILE *out_file;
15 } multiplexer_t;
17 typedef struct
19 long bytes_decoded;
20 long frames_decoded;
21 long samples_decoded;
22 mpeg3_t *file;
23 FILE *raw_file;
24 int stream_number;
25 int end_of_data;
26 } track_t;
28 int write_pack_header(unsigned char *ptr,
29 multiplexer_t *mplex,
30 float seconds,
31 int stream_id,
32 int ac3)
34 int packet_length;
35 // PACK START CODE
36 *ptr++ = 0x00;
37 *ptr++ = 0x00;
38 *ptr++ = 0x01;
39 *ptr++ = 0xba;
41 if(mplex->derivative == 1)
43 unsigned long timestamp = (unsigned long)(seconds * 90000);
44 *ptr = 0x20;
45 *ptr++ |= ((timestamp & 0xc0000000) >> 29) | 1;
46 *ptr++ = (timestamp & 0x3fc00000) >> 22;
47 *ptr++ = ((timestamp & 0x003f8000) >> 14) | 1;
48 *ptr++ = (timestamp & 0x00007f80) >> 7;
49 *ptr++ = ((timestamp & 0x0000007f) << 1) | 1;
51 *ptr++ = 0;
52 *ptr++ = 0;
53 *ptr++ = 0;
55 else
56 if(mplex->derivative == 2)
58 *ptr = 0x40;
61 *ptr++ = 0x00;
62 *ptr++ = 0x00;
63 *ptr++ = 0x01;
64 if(ac3)
65 *ptr++ = 0xbd;
66 else
67 *ptr++ = stream_id;
69 // Packet length
70 packet_length = PACKET_SIZE - (ptr - mplex->packet_buffer) - 2;
71 *ptr++ = (packet_length & 0xff00) >> 8;
72 *ptr++ = packet_length & 0xff;
74 // Pts/dts flags
75 *ptr++ = 0x0f;
77 // AC3 stream_id
78 if(ac3)
80 *ptr++ = stream_id;
81 *ptr++ = 0x00;
82 *ptr++ = 0x00;
83 *ptr++ = 0x00;
86 return PACKET_SIZE - (ptr - mplex->packet_buffer);
89 int write_packet(track_t *track,
90 float start_time,
91 float end_time,
92 multiplexer_t *mplex,
93 int stream_id,
94 int ac3)
96 int result = 0;
98 long bytes_needed = track->bytes_decoded - ftell(track->raw_file);
99 long current_byte = 0;
101 while(current_byte < bytes_needed)
103 // Write packet header
104 float current_time = start_time + (float)current_byte / bytes_needed * (end_time - start_time);
105 int packet_bytes = write_pack_header(mplex->packet_buffer,
106 mplex,
107 current_time,
108 stream_id,
109 ac3);
110 unsigned char *ptr = mplex->packet_buffer + PACKET_SIZE - packet_bytes;
111 int bytes_read = fread(ptr, 1, packet_bytes, track->raw_file);
113 result = !fwrite(mplex->packet_buffer, PACKET_SIZE, 1, mplex->out_file);
114 current_byte += packet_bytes;
116 return result;
119 void skip_frame(mpeg3_demuxer_t *demuxer)
121 unsigned long header = 0;
122 mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
125 header <<= 8;
126 header &= 0xffffffff;
127 header |= mpeg3io_read_char(title->fs);
128 }while(header != MPEG3_PICTURE_START_CODE && !mpeg3io_eof(title->fs));
131 * if(!mpeg3io_eof(title->fs))
132 * mpeg3io_seek_relative(title->fs, -4);
134 ((mpeg3_t*)demuxer->file)->last_type_read = 2;
137 int main(int argc, char *argv[])
139 int streams = 0;
140 int stream = 0;
141 int result = 0;
142 track_t *atracks[streams + 1];
143 track_t *vtracks[streams + 1];
144 int total_atracks = 0;
145 int total_vtracks = 0;
146 float frame_rate = 30000.0 / 1001.0;
147 float sample_rate = 48000;
148 long frames_decoded = 0;
149 float *audio_temp = malloc(1);
150 long audio_temp_allocated = 0;
151 float current_time = 0, previous_time = 0;
152 int video_completed = 0;
153 int audio_completed = 0;
154 int i;
155 int ac3 = 0;
156 multiplexer_t mplex;
157 char **path;
158 char *output_path;
159 int old_percentage = 0;
161 path = malloc(sizeof(char*) * argc);
162 mplex.derivative = 1;
163 mplex.out_file = 0;
165 if(argc < 4)
167 printf("Tiny MPLEX by Heroine Virtual Ltd.\n");
168 printf("Usage: mplex [-a] <stream 1> <stream2> ... <output>\n");
169 printf(" -a use ac3 packet headers\n");
170 exit(1);
173 for(i = 1; i < argc; i++)
175 if(!strcmp(argv[i], "-a"))
177 ac3 = 1;
179 else
180 if(i == argc - 1)
182 output_path = argv[i];
184 else
186 path[stream] = malloc(strlen(argv[i]) + 1);
187 strcpy(path[stream], argv[i]);
188 streams++;
189 stream++;
193 // Open files
194 for(stream = 0; stream < streams; stream++)
196 int is_audio, is_video;
197 int error_return;
198 mpeg3_t *file = mpeg3_open(path[stream], &error_return);
200 if(!file)
202 printf("Couldn't open %s\n", path[stream]);
203 result = 1;
205 else
207 is_audio = mpeg3_has_audio(file);
208 is_video = mpeg3_has_video(file);
209 mpeg3_set_cpus(file, 2);
211 if(is_audio && is_video)
213 printf("%s: Can't multiplex a system stream.\n", path[stream]);
214 result = 1;
216 else
217 if(is_audio)
219 atracks[total_atracks] = calloc(1, sizeof(track_t));
220 atracks[total_atracks]->file = file;
221 sample_rate = mpeg3_sample_rate(file, 0);
222 atracks[total_atracks]->raw_file = fopen(path[stream], "rb");
223 atracks[total_atracks]->stream_number = total_atracks;
224 total_atracks++;
226 else
227 if(is_video)
229 vtracks[total_vtracks] = calloc(1, sizeof(track_t));
230 vtracks[total_vtracks]->file = file;
231 frame_rate = mpeg3_frame_rate(file, 0);
232 vtracks[total_vtracks]->raw_file = fopen(path[stream], "rb");
233 vtracks[total_vtracks]->stream_number = total_vtracks;
234 // Get the first frame
235 skip_frame(vtracks[total_vtracks]->file->vtrack[0]->demuxer);
236 total_vtracks++;
238 else
240 printf("%s: Has neither audio or video.\n", path[stream]);
241 result = 1;
246 if(!result)
248 if(!total_vtracks)
250 printf("You must supply at least 1 video track.\n");
251 result = 1;
255 // Open output
256 if(!result)
257 if(!(mplex.out_file = fopen(output_path, "wb")))
259 printf("Couldn't open output file\n");
260 result = 1;
263 // Write multiplexed stream
264 if(!result)
266 while(!result && !(video_completed && audio_completed))
268 previous_time = current_time;
269 // Want the frame to come before the audio that goes with it.
270 for(stream = 0; stream < total_vtracks && !result; stream++)
272 // Decode a frame and write it
273 track_t *track = vtracks[stream];
275 if(!track->end_of_data)
277 int percentage;
278 skip_frame(track->file->vtrack[0]->demuxer);
279 track->frames_decoded++;
280 track->bytes_decoded = mpeg3demux_tell_byte(
281 track->file->vtrack[0]->demuxer);
282 if(track->frames_decoded > frames_decoded)
284 frames_decoded = track->frames_decoded;
285 current_time = (float)frames_decoded / frame_rate;
288 result = write_packet(track,
289 previous_time,
290 current_time,
291 &mplex,
292 0xe0 | track->stream_number,
294 track->end_of_data = mpeg3_end_of_video(track->file, 0);
295 percentage = (int)(mpeg3demux_tell_byte(track->file->vtrack[0]->demuxer) *
296 100 /
297 mpeg3demux_movie_size(track->file->vtrack[0]->demuxer));
298 if(percentage - old_percentage >= 1)
300 printf("\t%d%% completed\r", percentage);
301 old_percentage = percentage;
303 fflush(stdout);
307 // Decode audio until the last frame is covered
308 for(stream = 0; stream < total_atracks && !result; stream++)
310 track_t *track = atracks[stream];
311 //printf("mplex decode audio 1\n");
312 if(!track->end_of_data &&
313 (track->samples_decoded < current_time * sample_rate ||
314 video_completed))
316 if(!video_completed)
318 long samples_needed = (long)(current_time * sample_rate) - track->samples_decoded;
319 if(audio_temp_allocated < samples_needed)
321 free(audio_temp);
322 audio_temp = malloc(sizeof(float) * samples_needed);
323 audio_temp_allocated = samples_needed;
326 mpeg3_read_audio(track->file,
327 audio_temp,
330 samples_needed,
332 track->bytes_decoded = mpeg3demux_tell_byte(track->file->atrack[0]->demuxer);
333 if(!track->end_of_data) track->bytes_decoded -= 2048;
334 track->samples_decoded += samples_needed;
335 track->end_of_data = mpeg3_end_of_audio(track->file, 0);
337 else
339 track->bytes_decoded = mpeg3demux_movie_size(track->file->atrack[0]->demuxer);
340 track->end_of_data = 1;
343 //printf("mplex decode audio 2\n");
344 result = write_packet(track,
345 previous_time,
346 current_time,
347 &mplex,
348 ac3 ? track->stream_number : (0xc0 | track->stream_number),
349 ac3);
353 for(stream = 0; stream < total_vtracks; stream++)
355 if(vtracks[stream]->end_of_data) video_completed++;
357 if(video_completed < total_vtracks) video_completed = 0;
359 for(stream = 0; stream < total_atracks; stream++)
361 if(atracks[stream]->end_of_data) audio_completed++;
363 if(audio_completed < total_atracks) audio_completed = 0;
367 // Close streams
368 for(stream = 0; stream < total_atracks; stream++)
370 mpeg3_close(atracks[stream]->file);
371 fclose(atracks[stream]->raw_file);
372 free(atracks[stream]);
375 for(stream = 0; stream < total_vtracks; stream++)
377 mpeg3_close(vtracks[stream]->file);
378 fclose(vtracks[stream]->raw_file);
379 free(vtracks[stream]);
382 if(mplex.out_file) fclose(mplex.out_file);
384 return result;