void AVI_info(avi_t *avifile) { long frames, rate, mp3rate, chunks, tot_bytes; int width, height, format, chan, bits; int j, tracks, tmp; double fps; char *codec; frames = AVI_video_frames(avifile); width = AVI_video_width(avifile); height = AVI_video_height(avifile); fps = AVI_frame_rate(avifile); codec = AVI_video_compressor(avifile); printf("[avilib] V: %6.3f fps, codec=%s, frames=%ld, width=%d, height=%d\n", fps, ((strlen(codec)==0)? "RGB": codec), frames, width, height); tracks=AVI_audio_tracks(avifile); tmp=AVI_get_audio_track(avifile); for(j=0; j<tracks; ++j) { AVI_set_audio_track(avifile, j); rate = AVI_audio_rate(avifile); format = AVI_audio_format(avifile); chan = AVI_audio_channels(avifile); bits = AVI_audio_bits(avifile); mp3rate= AVI_audio_mp3rate(avifile); chunks = AVI_audio_chunks(avifile); tot_bytes = AVI_audio_bytes(avifile); if(chan>0) { printf("[avilib] A: %ld Hz, format=0x%02x, bits=%d, channels=%d, bitrate=%ld kbps,\n", rate, format, bits, chan, mp3rate); printf("[avilib] %ld chunks, %ld bytes, %s\n", chunks, tot_bytes, (AVI_get_audio_vbr(avifile)?"VBR":"CBR")); } else printf("[avilib] A: no audio track found\n"); } AVI_set_audio_track(avifile, tmp); //reset }
void avi_reader_c::identify_audio() { int i; for (i = 0; i < AVI_audio_tracks(m_avi); i++) { AVI_set_audio_track(m_avi, i); unsigned int audio_format = AVI_audio_format(m_avi); alWAVEFORMATEX *wfe = m_avi->wave_format_ex[i]; if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) { alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe); audio_format = get_uint32_le(&ext->extension.guid.data1); } std::string type = (0x0001 == audio_format) || (0x0003 == audio_format) ? "PCM" : (0x0050 == audio_format) ? "MP2" : (0x0055 == audio_format) ? "MP3" : (0x2000 == audio_format) ? "AC3" : (0x2001 == audio_format) ? "DTS" : (0x0050 == audio_format) ? "MP2" : (0x00ff == audio_format) || (0x706d == audio_format) ? "AAC" : (0x566f == audio_format) ? "Vorbis" : (boost::format("unsupported (0x%|1$04x|)") % audio_format).str(); id_result_track(i + 1, ID_RESULT_TRACK_AUDIO, type); } }
file_status_e avi_reader_c::read_audio(avi_demuxer_t &demuxer) { AVI_set_audio_track(m_avi, demuxer.m_aid); while (true) { int size = AVI_audio_size(m_avi, AVI_get_audio_position_index(m_avi)); if (-1 == size) return flush_packetizer(demuxer.m_ptzr); if (!size) { AVI_set_audio_position_index(m_avi, AVI_get_audio_position_index(m_avi) + 1); continue; } auto chunk = memory_c::alloc(size); size = AVI_read_audio_chunk(m_avi, reinterpret_cast<char *>(chunk->get_buffer())); if (0 >= size) continue; PTZR(demuxer.m_ptzr)->add_avi_block_size(size); PTZR(demuxer.m_ptzr)->process(new packet_t(chunk)); m_bytes_processed += size; return AVI_get_audio_position_index(m_avi) < AVI_max_audio_chunk(m_avi) ? FILE_STATUS_MOREDATA : flush_packetizer(demuxer.m_ptzr); } }
file_status_e avi_reader_c::read_audio(avi_demuxer_t &demuxer) { AVI_set_audio_track(m_avi, demuxer.m_aid); while (true) { int size = AVI_audio_size(m_avi, AVI_get_audio_position_index(m_avi)); // -1 indicates the last chunk. if (-1 == size) return flush_packetizer(demuxer.m_ptzr); // Sanity check. Ignore chunks with obvious wrong size information // (> 10 MB). Also skip 0-sized blocks. Those are officially // skipped. if (!size || (size > AVI_MAX_AUDIO_CHUNK_SIZE)) { AVI_set_audio_position_index(m_avi, AVI_get_audio_position_index(m_avi) + 1); continue; } auto chunk = memory_c::alloc(size); size = AVI_read_audio_chunk(m_avi, reinterpret_cast<char *>(chunk->get_buffer())); if (0 >= size) continue; PTZR(demuxer.m_ptzr)->process(new packet_t(chunk)); m_bytes_processed += size; return AVI_get_audio_position_index(m_avi) < AVI_max_audio_chunk(m_avi) ? FILE_STATUS_MOREDATA : flush_packetizer(demuxer.m_ptzr); } }
generic_packetizer_c * avi_reader_c::create_dts_packetizer(int aid) { try { AVI_set_audio_track(m_avi, aid); long audio_position = AVI_get_audio_position_index(m_avi); unsigned int num_read = 0; int dts_position = -1; byte_buffer_c buffer; dts_header_t dtsheader; while ((-1 == dts_position) && (10 > num_read)) { int chunk_size = AVI_read_audio_chunk(m_avi, nullptr); if (0 < chunk_size) { memory_cptr chunk = memory_c::alloc(chunk_size); AVI_read_audio_chunk(m_avi, reinterpret_cast<char *>(chunk->get_buffer())); buffer.add(chunk); dts_position = find_dts_header(buffer.get_buffer(), buffer.get_size(), &dtsheader); } else { dts_position = find_dts_header(buffer.get_buffer(), buffer.get_size(), &dtsheader, true); break; } } if (-1 == dts_position) throw false; AVI_set_audio_position_index(m_avi, audio_position); return new dts_packetizer_c(this, m_ti, dtsheader); } catch (...) { mxerror_tid(m_ti.m_fname, aid + 1, Y("Could not find valid DTS headers in this track's first frames.\n")); return nullptr; } }
void avi_reader_c::identify_audio() { int i; for (i = 0; i < AVI_audio_tracks(m_avi); i++) { AVI_set_audio_track(m_avi, i); auto info = mtx::id::info_c{}; info.add(mtx::id::audio_channels, AVI_audio_channels(m_avi)); info.add(mtx::id::audio_sampling_frequency, AVI_audio_rate(m_avi)); info.add(mtx::id::audio_bits_per_sample, AVI_audio_bits(m_avi)); unsigned int audio_format = AVI_audio_format(m_avi); alWAVEFORMATEX *wfe = m_avi->wave_format_ex[i]; if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) { alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe); audio_format = get_uint32_le(&ext->extension.guid.data1); } auto codec = codec_c::look_up_audio_format(audio_format); id_result_track(i + 1, ID_RESULT_TRACK_AUDIO, codec.get_name((boost::format("unsupported (0x%|1$04x|)") % audio_format).str()), info.get()); } }
int main(int argc, char *argv[]) { struct common_struct rtf; struct AVIStreamHeader ash, vsh; avi_t *avifile; int err, fd, id = 0, track_num = 0, n, ch, debug = TC_FALSE; int brate = 0, val1 = 0, val2 = 1, a_rate, a_chan, a_bits; long ah_off = 0, af_off = 0, vh_off = 0, vf_off = 0; char codec[5], *str = NULL, *filename = NULL; uint32_t change = CHANGE_NOTHING; ac_init(AC_ALL); if (argc==1) usage(EXIT_FAILURE); while ((ch = getopt(argc, argv, "df:i:N:F:vb:e:a:?h")) != -1) { switch (ch) { case 'N': VALIDATE_OPTION; id = strtol(optarg, NULL, 16); if (id < 0) { tc_log_error(EXE, "invalid parameter set for option -N"); } else { change |= CHANGE_AUDIO_FMT; } break; case 'a': VALIDATE_OPTION; track_num = atoi(optarg); if (track_num < 0) usage(EXIT_FAILURE); break; case 'f': VALIDATE_OPTION; n = sscanf(optarg,"%d,%d", &val1, &val2); if (n != 2 || val1 < 0 || val2 < 0) { tc_log_error(EXE, "invalid parameter set for option -f"); } else { change |= CHANGE_VIDEO_FPS; } break; case 'F': VALIDATE_OPTION; str = optarg; if(strlen(str) > 4 || strlen(str) == 0) { tc_log_error(EXE, "invalid parameter set for option -F"); } else { change |= CHANGE_VIDEO_FOURCC; } break; case 'i': VALIDATE_OPTION; filename = optarg; break; case 'b': VALIDATE_OPTION; brate = atoi(optarg); change |= CHANGE_AUDIO_BR; break; case 'v': version(); exit(0); case 'e': VALIDATE_OPTION; n = sscanf(optarg,"%d,%d,%d", &a_rate, &a_bits, &a_chan); switch (n) { case 3: change |= CHANGE_AUDIO_RATE; case 2: change |= CHANGE_AUDIO_BITS; case 1: change |= CHANGE_AUDIO_CHANS; break; default: tc_log_error(EXE, "invalid parameter set for option -e"); } break; case 'd': debug = TC_TRUE; break; case 'h': usage(EXIT_SUCCESS); default: usage(EXIT_FAILURE); } } if (!filename) usage(EXIT_FAILURE); tc_log_info(EXE, "scanning AVI-file %s for header information", filename); avifile = AVI_open_input_file(filename, 1); if (!avifile) { AVI_print_error("AVI open"); exit(1); } AVI_info(avifile); if (AVI_set_audio_track(avifile, track_num) < 0) { tc_log_error(EXE, "invalid audio track"); } ah_off = AVI_audio_codech_offset(avifile); af_off = AVI_audio_codecf_offset(avifile); vh_off = AVI_video_codech_offset(avifile); vf_off = AVI_video_codecf_offset(avifile); if (debug) { tc_log_info(EXE, "offsets: ah=%li af=%li vh=%li vf=%li", ah_off, af_off, vh_off, vf_off); } AVI_close(avifile); fd = open(filename, O_RDWR); if (fd < 0) { perror("open"); exit(1); } lseek(fd, vh_off, SEEK_SET); hdr_read("video codec [h]", fd, codec, 4); codec[4] = 0; lseek(fd, vf_off, SEEK_SET); hdr_read("video codec [f]", fd, codec, 4); codec[4] = 0; if (change & CHANGE_VIDEO_FPS) { lseek(fd, vh_off-4, SEEK_SET); hdr_read("video fps", fd, &vsh, sizeof(vsh)); vsh.dwRate = (long)val1; vsh.dwScale = (long)val2; lseek(fd, vh_off-4, SEEK_SET); hdr_write("video fps", fd, &vsh, sizeof(vsh)); } if (change & CHANGE_VIDEO_FOURCC) { lseek(fd,vh_off,SEEK_SET); if (strncmp(str,"RGB",3) == 0) { hdr_write("video 4cc", fd, codec, 4); } else { hdr_write("video 4cc", fd, str, 4); } lseek(fd,vf_off,SEEK_SET); if(strncmp(str,"RGB",3)==0) { memset(codec, 0, 4); hdr_write("video 4cc", fd, codec, 4); } else { hdr_write("video 4cc", fd, str, 4); } } if (NEED_AUDIO_CHANGE(change)) { lseek(fd, ah_off, SEEK_SET); hdr_read("audio header [h]", fd, &ash, sizeof(ash)); lseek(fd, af_off, SEEK_SET); hdr_read("audio header [f]", fd, &rtf, sizeof(rtf)); if (change & CHANGE_AUDIO_FMT) { rtf.wFormatTag = (unsigned short) id; } if (change & CHANGE_AUDIO_BR) { rtf.dwAvgBytesPerSec = (long) 1000*brate/8; ash.dwRate = (long) 1000*brate/8; ash.dwScale = 1; } if (change & CHANGE_AUDIO_CHANS) { rtf.wChannels = (short) a_chan; } if (change & CHANGE_AUDIO_BITS) { rtf.wBitsPerSample = (short) a_bits; } if (change & CHANGE_AUDIO_RATE) { rtf.dwSamplesPerSec = (long) a_rate; } lseek(fd, ah_off ,SEEK_SET); hdr_write("audio header [h]", fd, &ash, sizeof(ash)); lseek(fd, af_off ,SEEK_SET); hdr_write("audio header [f]", fd, &rtf, sizeof(rtf)); } err = close(fd); if (err) { perror("close"); exit(1); } avifile = AVI_open_input_file(filename, 1); if (!avifile) { AVI_print_error("AVI open"); exit(1); } tc_log_info(EXE, "updated AVI file %s", filename); AVI_info(avifile); AVI_close(avifile); return 0; }
void avi_reader_c::add_audio_demuxer(int aid) { for (auto &demuxer : m_audio_demuxers) if (demuxer.m_aid == aid) // Demuxer already added? return; AVI_set_audio_track(m_avi, aid); if (AVI_read_audio_chunk(m_avi, nullptr) < 0) { mxwarn(boost::format(Y("Could not find an index for audio track %1% (avilib error message: %2%). Skipping track.\n")) % (aid + 1) % AVI_strerror()); return; } avi_demuxer_t demuxer; generic_packetizer_c *packetizer = nullptr; alWAVEFORMATEX *wfe = m_avi->wave_format_ex[aid]; uint32_t audio_format = AVI_audio_format(m_avi); demuxer.m_aid = aid; demuxer.m_ptzr = -1; demuxer.m_samples_per_second = AVI_audio_rate(m_avi); demuxer.m_channels = AVI_audio_channels(m_avi); demuxer.m_bits_per_sample = AVI_audio_bits(m_avi); m_ti.m_id = aid + 1; // ID for this audio track. m_ti.m_avi_block_align = get_uint16_le(&wfe->n_block_align); m_ti.m_avi_avg_bytes_per_sec = get_uint32_le(&wfe->n_avg_bytes_per_sec); m_ti.m_avi_samples_per_chunk = get_uint32_le(&m_avi->stream_headers[aid].dw_scale); m_ti.m_avi_sample_scale = get_uint32_le(&m_avi->stream_headers[aid].dw_rate); m_ti.m_avi_samples_per_sec = demuxer.m_samples_per_second; if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) { alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe); audio_format = get_uint32_le(&ext->extension.guid.data1); } else if (get_uint16_le(&wfe->cb_size) > 0) m_ti.m_private_data = memory_c::clone(wfe + 1, get_uint16_le(&wfe->cb_size)); else m_ti.m_private_data.reset(); switch(audio_format) { case 0x0001: // raw PCM audio case 0x0003: // raw PCM audio (float) packetizer = new pcm_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, demuxer.m_bits_per_sample, 0x0003 == audio_format ? pcm_packetizer_c::ieee_float : pcm_packetizer_c::little_endian_integer); break; case 0x0050: // MP2 case 0x0055: // MP3 packetizer = new mp3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, false); break; case 0x2000: // AC3 packetizer = new ac3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, 0); break; case 0x2001: // DTS packetizer = create_dts_packetizer(aid); break; case 0x00ff: case 0x706d: // AAC packetizer = create_aac_packetizer(aid, demuxer); break; case 0x566f: // Vorbis packetizer = create_vorbis_packetizer(aid); break; default: mxerror_tid(m_ti.m_fname, aid + 1, boost::format(Y("Unknown/unsupported audio format 0x%|1$04x| for this audio track.\n")) % audio_format); } show_packetizer_info(aid + 1, packetizer); demuxer.m_ptzr = add_packetizer(packetizer); m_audio_demuxers.push_back(demuxer); int i, maxchunks = AVI_audio_chunks(m_avi); for (i = 0; i < maxchunks; i++) m_bytes_to_process += AVI_audio_size(m_avi, i); }
static int merger(avi_t *out, char *file) { avi_t *in; long frames, n, bytes; int key, j, aud_tracks; static int init = 0; static int vid_chunks = 0; double fps; static double vid_ms; static double aud_ms[AVI_MAX_TRACKS]; int have_printed=0; int do_drop_video=0; if (!init) { for (j=0; j<AVI_MAX_TRACKS; j++) aud_ms[j] = 0.0; vid_ms = 0; vid_chunks = 0; init = 1; } if(indexfile) { if (NULL == (in = AVI_open_input_indexfile(file, 0, indexfile))) { AVI_print_error("AVI open with indexfile"); return(-1); } } else if(NULL == (in = AVI_open_input_file(file,1))) { AVI_print_error("AVI open"); return(-1); } AVI_seek_start(in); fps = AVI_frame_rate(in); frames = AVI_video_frames(in); aud_tracks = AVI_audio_tracks(in); for (n=0; n<frames; ++n) { ++vid_chunks; vid_ms = vid_chunks*1000.0/fps; // audio for(j=0; j<aud_tracks; ++j) { int ret; double old_ms = aud_ms[j]; AVI_set_audio_track(in, j); AVI_set_audio_track(out, j); ret = sync_audio_video_avi2avi (vid_ms, &aud_ms[j], in, out); if (ret<0) { if (ret==-2) { if (aud_ms[j] == old_ms) { do_drop_video = 1; if (!have_printed) { fprintf(stderr, "\nNo audiodata left for track %d->%d (%.2f=%.2f) %s ..\n", AVI_get_audio_track(in), AVI_get_audio_track(out), old_ms, aud_ms[j], (do_drop_video && drop_video)?"breaking (-c)":"continuing"); have_printed++; } } } else { fprintf(stderr, "\nAn error happend at frame %ld track %d\n", n, j); } } } if (do_drop_video && drop_video) { fprintf(stderr, "\n[avimerge] Dropping %ld frames\n", frames-n-1); goto out; } // video bytes = AVI_read_frame(in, data, &key); if(bytes < 0) { AVI_print_error("AVI read video frame"); return(-1); } if(AVI_write_frame(out, data, bytes, key)<0) { AVI_print_error("AVI write video frame"); return(-1); } // progress fprintf(stderr, "[%s] (%06ld-%06ld) (%.2f <-> %.2f)\r", file, sum_frames, sum_frames + n, vid_ms, aud_ms[0]); } out: fprintf(stderr, "\n"); AVI_close(in); sum_frames += n; return(0); }
int main(int argc, char *argv[]) { avi_t *avifile, *avifile1, *avifile2; char *outfile=NULL, *infile=NULL, *audfile=NULL; long rate, mp3rate; int j, ch, cc=0, track_num=0, out_track_num=-1; int width, height, format=0, format_add, chan, bits, aud_error=0; double fps; char *codec; long offset, frames, n, bytes, aud_offset=0; int key; int aud_tracks; // for mp3 audio FILE *f=NULL; int len, headlen, chan_i, rate_i, mp3rate_i; unsigned long vid_chunks=0; char head[8]; off_t pos; double aud_ms = 0.0, vid_ms = 0.0; double aud_ms_w[AVI_MAX_TRACKS]; ac_init(AC_ALL); if(argc==1) usage(EXIT_FAILURE); while ((ch = getopt(argc, argv, "A:a:b:ci:o:p:f:x:?hv")) != -1) { switch (ch) { case 'i': if(optarg[0]=='-') usage(EXIT_FAILURE); infile = optarg; break; case 'A': if(optarg[0]=='-') usage(EXIT_FAILURE); out_track_num = atoi(optarg); if(out_track_num<-1) usage(EXIT_FAILURE); break; case 'a': if(optarg[0]=='-') usage(EXIT_FAILURE); track_num = atoi(optarg); if(track_num<0) usage(EXIT_FAILURE); break; case 'b': if(optarg[0]=='-') usage(EXIT_FAILURE); is_vbr = atoi(optarg); if(is_vbr<0) usage(EXIT_FAILURE); break; case 'c': drop_video = 1; break; case 'o': if(optarg[0]=='-') usage(EXIT_FAILURE); outfile = optarg; break; case 'p': if(optarg[0]=='-') usage(EXIT_FAILURE); audfile = optarg; break; case 'f': if(optarg[0]=='-') usage(EXIT_FAILURE); comfile = optarg; break; case 'x': if(optarg[0]=='-') usage(EXIT_FAILURE); indexfile = optarg; break; case 'v': version(); exit(EXIT_SUCCESS); case 'h': usage(EXIT_SUCCESS); default: usage(EXIT_FAILURE); } } if(outfile == NULL || infile == NULL) usage(EXIT_FAILURE); printf("scanning file %s for video/audio parameter\n", infile); // open first file for video/audio info read only if(indexfile) { if (NULL == (avifile1 = AVI_open_input_indexfile(infile,0,indexfile))) { AVI_print_error("AVI open with index file"); } } else if(NULL == (avifile1 = AVI_open_input_file(infile,1))) { AVI_print_error("AVI open"); exit(1); } AVI_info(avifile1); // safety checks if(strcmp(infile, outfile)==0) { printf("error: output filename conflicts with input filename\n"); exit(1); } ch = optind; while (ch < argc) { if(tc_file_check(argv[ch]) != 0) { printf("error: file not found\n"); exit(1); } if(strcmp(argv[ch++], outfile)==0) { printf("error: output filename conflicts with input filename\n"); exit(1); } } // open output file if(NULL == (avifile = AVI_open_output_file(outfile))) { AVI_print_error("AVI open"); exit(1); } // read video info; width = AVI_video_width(avifile1); height = AVI_video_height(avifile1); fps = AVI_frame_rate(avifile1); codec = AVI_video_compressor(avifile1); //set video in outputfile AVI_set_video(avifile, width, height, fps, codec); if (comfile!=NULL) AVI_set_comment_fd(avifile, open(comfile, O_RDONLY)); //multi audio tracks? aud_tracks = AVI_audio_tracks(avifile1); if (out_track_num < 0) out_track_num = aud_tracks; for(j=0; j<aud_tracks; ++j) { if (out_track_num == j) continue; AVI_set_audio_track(avifile1, j); rate = AVI_audio_rate(avifile1); chan = AVI_audio_channels(avifile1); bits = AVI_audio_bits(avifile1); format = AVI_audio_format(avifile1); mp3rate= AVI_audio_mp3rate(avifile1); //printf("TRACK %d MP3RATE %ld VBR %ld\n", j, mp3rate, AVI_get_audio_vbr(avifile1)); //set next track of output file AVI_set_audio_track(avifile, j); AVI_set_audio(avifile, chan, rate, bits, format, mp3rate); AVI_set_audio_vbr(avifile, AVI_get_audio_vbr(avifile1)); } if(audfile!=NULL) goto audio_merge; // close reopen in merger function AVI_close(avifile1); //------------------------------------------------------------- printf("merging multiple AVI-files (concatenating) ...\n"); // extract and write to new files printf ("file %02d %s\n", ++cc, infile); merger(avifile, infile); while (optind < argc) { printf ("file %02d %s\n", ++cc, argv[optind]); merger(avifile, argv[optind++]); } // close new AVI file AVI_close(avifile); printf("... done merging %d file(s) in %s\n", cc, outfile); // reopen file for video/audio info if(NULL == (avifile = AVI_open_input_file(outfile,1))) { AVI_print_error("AVI open"); exit(1); } AVI_info(avifile); return(0); //------------------------------------------------------------- // ************************************************* // Merge the audio track of an additional AVI file // ************************************************* audio_merge: printf("merging audio %s track %d (multiplexing) into %d ...\n", audfile, track_num, out_track_num); // open audio file read only if(NULL == (avifile2 = AVI_open_input_file(audfile,1))) { int f=open(audfile, O_RDONLY), ret=0; char head[1024], *c; c = head; if (f>0 && (1024 == read(f, head, 1024)) ) { while ((c-head<1024-8) && (ret = tc_probe_audio_header(c, 8))<=0 ) { c++; } close(f); if (ret > 0) { aud_offset = c-head; //printf("found atrack 0x%x off=%ld\n", ret, aud_offset); goto merge_mp3; } } AVI_print_error("AVI open"); exit(1); } AVI_info(avifile2); //switch to requested track if(AVI_set_audio_track(avifile2, track_num)<0) { fprintf(stderr, "invalid audio track\n"); } rate = AVI_audio_rate(avifile2); chan = AVI_audio_channels(avifile2); bits = AVI_audio_bits(avifile2); format = AVI_audio_format(avifile2); mp3rate= AVI_audio_mp3rate(avifile2); //set next track AVI_set_audio_track(avifile, out_track_num); AVI_set_audio(avifile, chan, rate, bits, format, mp3rate); AVI_set_audio_vbr(avifile, AVI_get_audio_vbr(avifile2)); AVI_seek_start(avifile1); frames = AVI_video_frames(avifile1); offset = 0; printf ("file %02d %s\n", ++cc, infile); for (n=0; n<AVI_MAX_TRACKS; n++) aud_ms_w[n] = 0.0; vid_chunks=0; for (n=0; n<frames; ++n) { // video bytes = AVI_read_frame(avifile1, data, &key); if(bytes < 0) { AVI_print_error("AVI read video frame"); return(-1); } if(AVI_write_frame(avifile, data, bytes, key)<0) { AVI_print_error("AVI write video frame"); return(-1); } ++vid_chunks; vid_ms = vid_chunks*1000.0/fps; for(j=0; j<aud_tracks; ++j) { if (j == out_track_num) continue; AVI_set_audio_track(avifile1, j); AVI_set_audio_track(avifile, j); chan = AVI_audio_channels(avifile1); // audio chan = AVI_audio_channels(avifile1); if(chan) { sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile); } } // merge additional track // audio chan = AVI_audio_channels(avifile2); AVI_set_audio_track(avifile, out_track_num); if(chan) { sync_audio_video_avi2avi(vid_ms, &aud_ms, avifile2, avifile); } // progress fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n); } fprintf(stderr,"\n"); offset = frames; //more files to merge? AVI_close(avifile1); while (optind < argc) { printf ("file %02d %s\n", ++cc, argv[optind]); if(NULL == ( avifile1 = AVI_open_input_file(argv[optind++],1))) { AVI_print_error("AVI open"); goto finish; } AVI_seek_start(avifile1); frames = AVI_video_frames(avifile1); for (n=0; n<frames; ++n) { // video bytes = AVI_read_frame(avifile1, data, &key); if(bytes < 0) { AVI_print_error("AVI read video frame"); return(-1); } if(AVI_write_frame(avifile, data, bytes, key)<0) { AVI_print_error("AVI write video frame"); return(-1); } ++vid_chunks; vid_ms = vid_chunks*1000.0/fps; // audio for(j=0; j<aud_tracks; ++j) { if (j == out_track_num) continue; AVI_set_audio_track(avifile1, j); AVI_set_audio_track(avifile, j); chan = AVI_audio_channels(avifile1); if(chan) { sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile); } } // merge additional track chan = AVI_audio_channels(avifile2); AVI_set_audio_track(avifile, out_track_num); if(chan) { sync_audio_video_avi2avi(vid_ms, &aud_ms, avifile2, avifile); } // chan // progress fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n); } fprintf(stderr, "\n"); offset += frames; AVI_close(avifile1); } finish: // close new AVI file printf("... done multiplexing in %s\n", outfile); AVI_info(avifile); AVI_close(avifile); return(0); // ************************************************* // Merge a raw audio file which is either MP3 or AC3 // ************************************************* merge_mp3: f = fopen(audfile,"rb"); if (!f) { perror ("fopen"); exit(1); } fseek(f, aud_offset, SEEK_SET); len = fread(head, 1, 8, f); format_add = tc_probe_audio_header(head, len); headlen = tc_get_audio_header(head, len, format_add, &chan_i, &rate_i, &mp3rate_i); fprintf(stderr, "... this looks like a %s track ...\n", (format_add==0x55)?"MP3":"AC3"); fseek(f, aud_offset, SEEK_SET); //set next track AVI_set_audio_track(avifile, out_track_num); AVI_set_audio(avifile, chan_i, rate_i, 16, format_add, mp3rate_i); AVI_set_audio_vbr(avifile, is_vbr); AVI_seek_start(avifile1); frames = AVI_video_frames(avifile1); offset = 0; for (n=0; n<AVI_MAX_TRACKS; ++n) aud_ms_w[n] = 0.0; for (n=0; n<frames; ++n) { // video bytes = AVI_read_frame(avifile1, data, &key); if(bytes < 0) { AVI_print_error("AVI read video frame"); return(-1); } if(AVI_write_frame(avifile, data, bytes, key)<0) { AVI_print_error("AVI write video frame"); return(-1); } vid_chunks++; vid_ms = vid_chunks*1000.0/fps; for(j=0; j<aud_tracks; ++j) { if (j == out_track_num) continue; AVI_set_audio_track(avifile1, j); AVI_set_audio_track(avifile, j); chan = AVI_audio_channels(avifile1); if(chan) { sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile); } } // merge additional track if(headlen>4 && !aud_error) { while (aud_ms < vid_ms) { //printf("reading Audio Chunk ch(%ld) vms(%lf) ams(%lf)\n", vid_chunks, vid_ms, aud_ms); pos = ftell(f); len = fread (head, 1, 8, f); if (len<=0) { //eof fprintf(stderr, "EOF in %s; continuing ..\n", audfile); aud_error=1; break; } if ( (headlen = tc_get_audio_header(head, len, format_add, NULL, NULL, &mp3rate_i))<0) { fprintf(stderr, "Broken %s track #(%d)? skipping\n", (format_add==0x55?"MP3":"AC3"), aud_tracks); aud_ms = vid_ms; aud_error=1; } else { // look in import/tcscan.c for explanation aud_ms += (headlen*8.0)/(mp3rate_i); } fseek (f, pos, SEEK_SET); len = fread (data, headlen, 1, f); if (len<=0) { //eof fprintf(stderr, "EOF in %s; continuing ..\n", audfile); aud_error=1; break; } AVI_set_audio_track(avifile, out_track_num); if(AVI_write_audio(avifile, data, headlen)<0) { AVI_print_error("AVI write audio frame"); return(-1); } } } // progress fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n); } fprintf(stderr,"\n"); offset = frames; // more files? while (optind < argc) { printf ("file %02d %s\n", ++cc, argv[optind]); if(NULL == ( avifile1 = AVI_open_input_file(argv[optind++],1))) { AVI_print_error("AVI open"); goto finish; } AVI_seek_start(avifile1); frames = AVI_video_frames(avifile1); for (n=0; n<frames; ++n) { // video bytes = AVI_read_frame(avifile1, data, &key); if(bytes < 0) { AVI_print_error("AVI read video frame"); return(-1); } if(AVI_write_frame(avifile, data, bytes, key)<0) { AVI_print_error("AVI write video frame"); return(-1); } vid_chunks++; vid_ms = vid_chunks*1000.0/fps; for(j=0; j<aud_tracks; ++j) { if (j == out_track_num) continue; AVI_set_audio_track(avifile1, j); AVI_set_audio_track(avifile, j); chan = AVI_audio_channels(avifile1); if(chan) { sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile); } } // merge additional track // audio if(headlen>4 && !aud_error) { while (aud_ms < vid_ms) { //printf("reading Audio Chunk ch(%ld) vms(%lf) ams(%lf)\n", vid_chunks, vid_ms, aud_ms); pos = ftell(f); len = fread (head, 8, 1, f); if (len<=0) { //eof fprintf(stderr, "EOF in %s; continuing ..\n", audfile); aud_error=1; break; } if ( (headlen = tc_get_audio_header(head, len, format_add, NULL, NULL, &mp3rate_i))<0) { fprintf(stderr, "Broken %s track #(%d)?\n", (format_add==0x55?"MP3":"AC3"), aud_tracks); aud_ms = vid_ms; aud_error=1; } else { // look in import/tcscan.c for explanation aud_ms += (headlen*8.0)/(mp3rate_i); } fseek (f, pos, SEEK_SET); len = fread (data, headlen, 1, f); if (len<=0) { //eof fprintf(stderr, "EOF in %s; continuing ..\n", audfile); aud_error=1; break; } AVI_set_audio_track(avifile, out_track_num); if(AVI_write_audio(avifile, data, headlen)<0) { AVI_print_error("AVI write audio frame"); return(-1); } } } // progress fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n); } fprintf(stderr, "\n"); offset += frames; AVI_close(avifile1); } if (f) fclose(f); printf("... done multiplexing in %s\n", outfile); AVI_close(avifile); return(0); }
void avi_reader_c::add_audio_demuxer(int aid) { for (auto &demuxer : m_audio_demuxers) if (demuxer.m_aid == aid) // Demuxer already added? return; AVI_set_audio_track(m_avi, aid); if (AVI_read_audio_chunk(m_avi, nullptr) < 0) { mxwarn(boost::format(Y("Could not find an index for audio track %1% (avilib error message: %2%). Skipping track.\n")) % (aid + 1) % AVI_strerror()); return; } avi_demuxer_t demuxer; generic_packetizer_c *packetizer = nullptr; alWAVEFORMATEX *wfe = m_avi->wave_format_ex[aid]; uint32_t audio_format = AVI_audio_format(m_avi); demuxer.m_aid = aid; demuxer.m_ptzr = -1; demuxer.m_samples_per_second = AVI_audio_rate(m_avi); demuxer.m_channels = AVI_audio_channels(m_avi); demuxer.m_bits_per_sample = AVI_audio_bits(m_avi); m_ti.m_id = aid + 1; // ID for this audio track. auto stream_header = &m_avi->stream_headers[aid]; auto dw_scale = static_cast<int64_t>(get_uint32_le(&stream_header->dw_scale)); auto dw_rate = static_cast<int64_t>(get_uint32_le(&stream_header->dw_rate)); auto dw_sample_size = static_cast<int64_t>(get_uint32_le(&stream_header->dw_sample_size)); m_ti.m_avi_audio_data_rate = dw_scale ? dw_rate * dw_sample_size / dw_scale : 0; if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) { alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe); audio_format = get_uint32_le(&ext->extension.guid.data1); } else if (get_uint16_le(&wfe->cb_size) > 0) m_ti.m_private_data = memory_c::clone(wfe + 1, get_uint16_le(&wfe->cb_size)); else m_ti.m_private_data.reset(); demuxer.m_codec = codec_c::look_up_audio_format(audio_format); if (demuxer.m_codec.is(codec_c::type_e::A_PCM)) packetizer = new pcm_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, demuxer.m_bits_per_sample, 0x0003 == audio_format ? pcm_packetizer_c::ieee_float : pcm_packetizer_c::little_endian_integer); else if (demuxer.m_codec.is(codec_c::type_e::A_MP2) || demuxer.m_codec.is(codec_c::type_e::A_MP3)) packetizer = new mp3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, false); else if (demuxer.m_codec.is(codec_c::type_e::A_AC3)) packetizer = new ac3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, 0); else if (demuxer.m_codec.is(codec_c::type_e::A_DTS)) packetizer = create_dts_packetizer(aid); else if (demuxer.m_codec.is(codec_c::type_e::A_AAC)) packetizer = create_aac_packetizer(aid, demuxer); else if (demuxer.m_codec.is(codec_c::type_e::A_VORBIS)) packetizer = create_vorbis_packetizer(aid); else mxerror_tid(m_ti.m_fname, aid + 1, boost::format(Y("Unknown/unsupported audio format 0x%|1$04x| for this audio track.\n")) % audio_format); packetizer->enable_avi_audio_sync(true); show_packetizer_info(aid + 1, packetizer); demuxer.m_ptzr = add_packetizer(packetizer); m_audio_demuxers.push_back(demuxer); int i, maxchunks = AVI_audio_chunks(m_avi); for (i = 0; i < maxchunks; i++) { auto size = AVI_audio_size(m_avi, i); if (size < AVI_MAX_AUDIO_CHUNK_SIZE) m_bytes_to_process += size; } }
int main(int argc, char *argv[]) { avi_t *avifile1=NULL; avi_t *avifile2=NULL; avi_t *avifile3=NULL; char *in_file=NULL, *out_file=NULL; long frames, bytes; double fps; char *codec; int track_num=0, aud_tracks; int encode_null=0; int i, j, n, key, shift=0; int ch, preload=0; long rate, mp3rate; int width, height, format, chan, bits; int be_quiet = 0; FILE *status_fd = stderr; /* for null frame encoding */ char nulls[32000]; long nullbytes=0; char tmp0[] = "/tmp/nullfile.00.avi"; /* XXX: use mktemp*() */ buffer_list_t *ptr; double vid_ms = 0.0, shift_ms = 0.0, one_vid_ms = 0.0; double aud_ms [ AVI_MAX_TRACKS ]; int aud_bitrate = 0; int aud_chunks = 0; ac_init(AC_ALL); if(argc==1) usage(EXIT_FAILURE); while ((ch = getopt(argc, argv, "a:b:vi:o:n:Nq?h")) != -1) { switch (ch) { case 'i': if(optarg[0]=='-') usage(EXIT_FAILURE); in_file=optarg; break; case 'a': if(optarg[0]=='-') usage(EXIT_FAILURE); track_num = atoi(optarg); if(track_num<0) usage(EXIT_FAILURE); break; case 'b': if(optarg[0]=='-') usage(EXIT_FAILURE); is_vbr = atoi(optarg); if(is_vbr<0) usage(EXIT_FAILURE); break; case 'o': if(optarg[0]=='-') usage(EXIT_FAILURE); out_file=optarg; break; case 'f': if(optarg[0]=='-') usage(EXIT_FAILURE); comfile = optarg; break; case 'n': if(sscanf(optarg,"%d", &shift)!=1) { fprintf(stderr, "invalid parameter for option -n\n"); usage(EXIT_FAILURE); } break; case 'N': encode_null=1; break; case 'q': be_quiet = 1; break; case 'v': version(); exit(0); break; case 'h': usage(EXIT_SUCCESS); default: usage(EXIT_FAILURE); } } // check if(in_file==NULL || out_file == NULL) usage(EXIT_FAILURE); if(shift == 0) fprintf(stderr, "no sync requested - exit"); memset (nulls, 0, sizeof(nulls)); // open file if(NULL == (avifile1 = AVI_open_input_file(in_file,1))) { AVI_print_error("AVI open"); exit(1); } if(strcmp(in_file, out_file)==0) { printf("error: output filename conflicts with input filename\n"); exit(1); } if(NULL == (avifile2 = AVI_open_output_file(out_file))) { AVI_print_error("AVI open"); exit(1); } if (be_quiet) { if (!(status_fd = fopen("/dev/null", "w"))) { fprintf(stderr, "Can't open /dev/null\n"); exit(1); } } // read video info; AVI_info(avifile1); // read video info; frames = AVI_video_frames(avifile1); width = AVI_video_width(avifile1); height = AVI_video_height(avifile1); fps = AVI_frame_rate(avifile1); codec = AVI_video_compressor(avifile1); //set video in outputfile AVI_set_video(avifile2, width, height, fps, codec); if (comfile!=NULL) AVI_set_comment_fd(avifile2, open(comfile, O_RDONLY)); aud_tracks = AVI_audio_tracks(avifile1); for(j=0; j<aud_tracks; ++j) { AVI_set_audio_track(avifile1, j); rate = AVI_audio_rate(avifile1); chan = AVI_audio_channels(avifile1); bits = AVI_audio_bits(avifile1); format = AVI_audio_format(avifile1); mp3rate= AVI_audio_mp3rate(avifile1); //set next track of output file AVI_set_audio_track(avifile2, j); AVI_set_audio(avifile2, chan, rate, bits, format, mp3rate); AVI_set_audio_vbr(avifile2, is_vbr); } //switch to requested audio_channel if(AVI_set_audio_track(avifile1, track_num)<0) { fprintf(stderr, "invalid auto track\n"); } AVI_set_audio_track(avifile2, track_num); if (encode_null) { char cmd[1024]; rate = AVI_audio_rate(avifile2); chan = AVI_audio_channels(avifile2); bits = AVI_audio_bits(avifile2); format = AVI_audio_format(avifile2); mp3rate= AVI_audio_mp3rate(avifile2); if (bits==0) bits=16; if (mp3rate%2) mp3rate++; fprintf(status_fd, "Creating silent mp3 frame with current parameter\n"); memset (cmd, 0, sizeof(cmd)); tc_snprintf(cmd, sizeof(cmd), "transcode -i /dev/zero -o %s -x raw,raw" " -n 0x1 -g 16x16 -y raw,raw -c 0-5 -e %ld,%d,%d -b %ld -q0", tmp0, rate,bits,chan, mp3rate); printf(cmd); system(cmd); if(NULL == (avifile3 = AVI_open_input_file(tmp0,1))) { AVI_print_error("AVI open"); exit(1); } nullbytes = AVI_audio_size(avifile3, 3); /* just read a few frames */ if(AVI_read_audio(avifile3, nulls, nullbytes) < 0) { AVI_print_error("AVI audio read frame"); return(-1); } memset (nulls, 0, sizeof(nulls)); if(AVI_read_audio(avifile3, nulls, nullbytes) < 0) { AVI_print_error("AVI audio read frame"); return(-1); } memset (nulls, 0, sizeof(nulls)); if(AVI_read_audio(avifile3, nulls, nullbytes) < 0) { AVI_print_error("AVI audio read frame"); return(-1); } /* printf("\nBytes (%ld): \n", nullbytes); { int asd=0; for (asd=0; asd<nullbytes; asd++){ printf("%x ",(unsigned char)nulls[asd]); } printf("\n"); } */ } vid_ms = 0.0; shift_ms = 0.0; for (n=0; n<AVI_MAX_TRACKS; ++n) aud_ms[n] = 0.0; // --------------------------------------------------------------------- for (n=0; n<frames; ++n) { // video unchanged bytes = AVI_read_frame(avifile1, data, &key); if(bytes < 0) { AVI_print_error("AVI read video frame"); return(-1); } if(AVI_write_frame(avifile2, data, bytes, key)<0) { AVI_print_error("AVI write video frame"); return(-1); } vid_ms = (n+1)*1000.0/fps; // Pass-through all other audio tracks. for(j=0; j<aud_tracks; ++j) { // skip track we want to modify if (j == track_num) continue; // switch to track AVI_set_audio_track(avifile1, j); AVI_set_audio_track(avifile2, j); sync_audio_video_avi2avi(vid_ms, &aud_ms[j], avifile1, avifile2); } //switch to requested audio_channel if(AVI_set_audio_track(avifile1, track_num)<0) { fprintf(stderr, "invalid auto track\n"); } AVI_set_audio_track(avifile2, track_num); shift_ms = (double)shift*1000.0/fps; one_vid_ms = 1000.0/fps; format = AVI_audio_format(avifile1); rate = AVI_audio_rate(avifile1); chan = AVI_audio_channels(avifile1); bits = AVI_audio_bits(avifile1); bits = bits==0?16:bits; mp3rate= AVI_audio_mp3rate(avifile1); if(shift>0) { // for n < shift, shift audio frames are discarded if(!preload) { if (tc_format_ms_supported(format)) { for(i=0;i<shift;++i) { //fprintf (stderr, "shift (%d) i (%d) n (%d) a (%d)\n", shift, i, n, aud_chunks); while (aud_ms[track_num] < vid_ms + one_vid_ms*(double)i) { aud_bitrate = (format==0x1||format==0x2000)?1:0; aud_chunks++; if( (bytes = AVI_read_audio_chunk(avifile1, data)) <= 0) { aud_ms[track_num] = vid_ms + one_vid_ms*i; if (bytes == 0) continue; AVI_print_error("AVI 2 audio read frame"); break; } if ( !aud_bitrate && tc_get_audio_header(data, bytes, format, NULL, NULL, &aud_bitrate)<0) { // if this is the last frame of the file, slurp in audio chunks if (n == frames-1) continue; aud_ms[track_num] = vid_ms + one_vid_ms*i; } else aud_ms[track_num] += (bytes*8.0)/(format==0x1?((double)(rate*chan*bits)/1000.0): (format==0x2000?(double)(mp3rate):aud_bitrate)); } } } else { // fallback bytes=0; for(i=0;i<shift;++i) { do { if( (bytes = AVI_read_audio_chunk(avifile1, data)) < 0) { AVI_print_error("AVI audio read frame"); return(-1); } } while (AVI_can_read_audio(avifile1)); } } preload=1; } // copy rest of the track if(n<frames-shift) { if (tc_format_ms_supported(format)) { while (aud_ms[track_num] < vid_ms + shift_ms) { aud_chunks++; aud_bitrate = (format==0x1||format==0x2000)?1:0; if( (bytes = AVI_read_audio_chunk(avifile1, data)) < 0) { aud_ms[track_num] = vid_ms + shift_ms; AVI_print_error("AVI 3 audio read frame"); break; } if(AVI_write_audio(avifile2, data, bytes) < 0) { AVI_print_error("AVI 3 write audio frame"); return(-1); } fprintf(status_fd, "V [%05d][%08.2f] | A [%05d][%08.2f] [%05ld]\r", n, vid_ms, aud_chunks, aud_ms[track_num], bytes); if (bytes == 0) { aud_ms[track_num] = vid_ms + shift_ms; continue; } if(n>=frames-2*shift) { // save audio frame for later ptr = buffer_register(n); if(ptr==NULL) { fprintf(stderr,"buffer allocation failed\n"); break; } ac_memcpy(ptr->data, data, bytes); ptr->size = bytes; ptr->status = BUFFER_READY; } if ( !aud_bitrate && tc_get_audio_header(data, bytes, format, NULL, NULL, &aud_bitrate)<0) { if (n == frames-1) continue; aud_ms[track_num] = vid_ms + shift_ms; } else aud_ms[track_num] += (bytes*8.0)/(format==0x1?((double)(rate*chan*bits)/1000.0): (format==0x2000?(double)(mp3rate):aud_bitrate)); } } else { // fallback bytes = AVI_audio_size(avifile1, n+shift-1); do { if( (bytes = AVI_read_audio_chunk(avifile1, data)) < 0) { AVI_print_error("AVI audio read frame"); return(-1); } if(AVI_write_audio(avifile2, data, bytes) < 0) { AVI_print_error("AVI write audio frame"); return(-1); } fprintf(status_fd, "V [%05d] | A [%05d] [%05ld]\r", n, n+shift, bytes); if(n>=frames-2*shift) { // save audio frame for later ptr = buffer_register(n); if(ptr==NULL) { fprintf(stderr,"buffer allocation failed\n"); break; } ac_memcpy(ptr->data, data, bytes); ptr->size = bytes; ptr->status = BUFFER_READY; } } while (AVI_can_read_audio(avifile1)); } } // padding at the end if(n>=frames-shift) { if (!ptrlen) { ptr = buffer_retrieve(); ac_memcpy (ptrdata, ptr->data, ptr->size); ptrlen = ptr->size; } if (tc_format_ms_supported(format)) { while (aud_ms[track_num] < vid_ms + shift_ms) { aud_bitrate = (format==0x1||format==0x2000)?1:0; // mute this -- check if can mute (valid A header)! if (tc_probe_audio_header(ptrdata, ptrlen) > 0) tc_format_mute(ptrdata, ptrlen, format); if(AVI_write_audio(avifile2, ptrdata, ptrlen) < 0) { AVI_print_error("AVI write audio frame"); return(-1); } fprintf(status_fd, " V [%05d][%08.2f] | A [%05d][%08.2f] [%05ld]\r", n, vid_ms, n+shift, aud_ms[track_num], bytes); if ( !aud_bitrate && tc_get_audio_header(ptrdata, ptrlen, format, NULL, NULL, &aud_bitrate)<0) { //if (n == frames-1) continue; aud_ms[track_num] = vid_ms + shift_ms; } else aud_ms[track_num] += (ptrlen*8.0)/(format==0x1?((double)(rate*chan*bits)/1000.0): (format==0x2000?(double)(mp3rate):aud_bitrate)); } } else { // fallback // get next audio frame ptr = buffer_retrieve(); while (1) { printf("ptr->id (%d) ptr->size (%d)\n", ptr->id, ptr->size); if(ptr==NULL) { fprintf(stderr,"no buffer found\n"); break; } if (encode_null) { if(AVI_write_audio(avifile2, nulls, nullbytes)<0) { AVI_print_error("AVI write audio frame"); return(-1); } } else { // simple keep old frames to force exact time delay if(AVI_write_audio(avifile2, ptr->data, ptr->size)<0) { AVI_print_error("AVI write audio frame"); return(-1); } } fprintf(status_fd, "V [%05d] | padding\r", n); if (ptr->next && ptr->next->id == ptr->id) { buffer_remove(ptr); ptr = buffer_retrieve(); continue; } buffer_remove(ptr); break; } // 1 } } // ************************************* // negative shift (pad audio at start) // ************************************* } else { if (tc_format_ms_supported(format)) { /* fprintf(status_fd, "n(%d) -shift(%d) shift_ms (%.2lf) vid_ms(%.2lf) aud_ms[%d](%.2lf) v-s(%.2lf)\n", n, -shift, shift_ms, vid_ms, track_num, aud_ms[track_num], vid_ms + shift_ms); */ // shift<0 -> shift_ms<0 ! while (aud_ms[track_num] < vid_ms) { /* fprintf(stderr, " 1 (%02d) %s frame_read len=%4ld (A/V) (%8.2f/%8.2f)\n", n, format==0x55?"MP3":"AC3", bytes, aud_ms[track_num], vid_ms); */ aud_bitrate = (format==0x1||format==0x2000)?1:0; if( (bytes = AVI_read_audio_chunk(avifile1, data)) < 0) { AVI_print_error("AVI 2 audio read frame"); aud_ms[track_num] = vid_ms; break; //return(-1); } // save audio frame for later ptr = buffer_register(n); if(ptr==NULL) { fprintf(stderr,"buffer allocation failed\n"); break; } ac_memcpy(ptr->data, data, bytes); ptr->size = bytes; ptr->status = BUFFER_READY; if(n<-shift) { // mute this -- check if can mute! if (tc_probe_audio_header(data, bytes) > 0) tc_format_mute(data, bytes, format); // simple keep old frames to force exact time delay if(AVI_write_audio(avifile2, data, bytes)<0) { AVI_print_error("AVI write audio frame"); return(-1); } fprintf(status_fd, "V [%05d] | padding\r", n); } else { if (n==-shift) fprintf(status_fd, "\n"); // get next audio frame ptr = buffer_retrieve(); if(ptr==NULL) { fprintf(stderr,"no buffer found\n"); break; } if(AVI_write_audio(avifile2, ptr->data, ptr->size)<0) { AVI_print_error("AVI write audio frame"); return(-1); } bytes = ptr->size; ac_memcpy (data, ptr->data, bytes); fprintf(status_fd, "V [%05d] | A [%05d]\r", n, ptr->id); buffer_remove(ptr); } if ( !aud_bitrate && tc_get_audio_header(data, bytes, format, NULL, NULL, &aud_bitrate)<0) { if (n == frames-1) continue; aud_ms[track_num] = vid_ms; } else aud_ms[track_num] += (bytes*8.0)/(format==0x1?((double)(rate*chan*bits)/1000.0): (format==0x2000?(double)(mp3rate):aud_bitrate)); /* fprintf(stderr, " 1 (%02d) %s frame_read len=%4ld (A/V) (%8.2f/%8.2f)\n", n, format==0x55?"MP3":"AC3", bytes, aud_ms[track_num], vid_ms); */ } } else { // no supported format bytes = AVI_audio_size(avifile1, n); if(bytes > SIZE_RGB_FRAME) { fprintf(stderr, "invalid frame size\n"); return(-1); } if(AVI_read_audio(avifile1, data, bytes) < 0) { AVI_print_error("AVI audio read frame"); return(-1); } // save audio frame for later ptr = buffer_register(n); if(ptr==NULL) { fprintf(stderr,"buffer allocation failed\n"); break; } ac_memcpy(ptr->data, data, bytes); ptr->size = bytes; ptr->status = BUFFER_READY; if(n<-shift) { if (encode_null) { if(AVI_write_audio(avifile2, nulls, nullbytes)<0) { AVI_print_error("AVI write audio frame"); return(-1); } } else { // simple keep old frames to force exact time delay if(AVI_write_audio(avifile2, data, bytes)<0) { AVI_print_error("AVI write audio frame"); return(-1); } } fprintf(status_fd, "V [%05d] | padding\r", n); } else { // get next audio frame ptr = buffer_retrieve(); if(ptr==NULL) { fprintf(stderr,"no buffer found\n"); break; } if(AVI_write_audio(avifile2, ptr->data, ptr->size)<0) { AVI_print_error("AVI write audio frame"); return(-1); } fprintf(status_fd, "V [%05d] | A [%05d]\r", n, ptr->id); buffer_remove(ptr); } } } } fprintf(status_fd, "\n"); if (be_quiet) { fclose(status_fd); } AVI_close(avifile1); AVI_close(avifile2); if (avifile3) { memset(nulls, 0, sizeof(nulls)); tc_snprintf(nulls, sizeof(nulls), "rm -f %s", tmp0); system(nulls); AVI_close(avifile3); } return(0); }