コード例 #1
0
ファイル: avi_bytestream.cpp プロジェクト: HunterChen/mpeg4ip
bool CAviAudioByteStream::start_next_frame (uint8_t **buffer, 
					    uint32_t *buflen,
					    frame_timestamp_t *ts,
					    void **ud)
{
  int value;
  if (m_buffer_on < m_this_frame_size) {
    value = m_this_frame_size - m_buffer_on;
    memmove(m_buffer,
	    m_buffer + m_buffer_on,
	    m_this_frame_size - m_buffer_on);
    m_this_frame_size -= m_buffer_on;
  } else {
    value = 0;
    m_this_frame_size = 0;
  }
  m_buffer_on = 0;
  m_parent->lock_file_mutex();
  AVI_set_audio_position(m_parent->get_file(), m_file_pos);

  int ret;
  ret = AVI_read_audio(m_parent->get_file(), 
		       (char *)m_buffer + value, 
		       m_max_frame_size - m_this_frame_size);
  m_parent->unlock_file_mutex();

  //player_debug_message("return from avi read %d", ret);
  m_this_frame_size += ret;
  m_file_pos += ret;
  if (m_file_pos >= AVI_audio_bytes(m_parent->get_file())) {
    m_eof = 1;
  }

  *buffer = m_buffer;
  *buflen = m_this_frame_size;
#if 0
  uint64_t ret;
  ret = m_frame_on;
  ret *= m_samples_per_frame;
  ret *= 1000;
  ret /= m_frame_rate;
    player_debug_message("Start next frame "U64 " offset %u %u", 
			 ret, m_byte_on, m_this_frame_size);
  return (ret);
#endif
  ts->msec_timestamp = 0;
  ts->audio_freq_timestamp = 0;
  ts->audio_freq = AVI_audio_rate(m_parent->get_file());
  ts->timestamp_is_pts = false;
  return true;
}
コード例 #2
0
ファイル: avi2raw.c プロジェクト: BluePandaLi/mpeg4ip
/*
 * avi2raw
 * required arg1 should be the input AVI file
 * required arg2 should be the output RAW file
 */ 
int main(int argc, char** argv)
{
	/* configurable variables from command line */
	bool extractVideo = TRUE;	/* FALSE implies extract audio */
	u_int32_t start = 0;		/* secs, start offset */
	u_int32_t duration = 0;		/* secs, 0 implies entire file */
	bool quiet = FALSE;		

	/* internal variables */
	char* aviFileName = NULL;
	char* rawFileName = NULL;
	avi_t* aviFile = NULL;
	FILE* rawFile = NULL;
	int verbose = FALSE;
	u_int32_t numBytes, totBytes = 0;
	bool eliminate_short_frames = FALSE;
	uint32_t short_frames_len;
	/* begin process command line */
	progName = argv[0];
	while (1) {
		int c = -1;
		int option_index = 0;
		static struct option long_options[] = {
			{ "audio", 0, 0, 'a' },
			{ "eliminate-short-frames", optional_argument, 0, 'e'},
			{ "length", 1, 0, 'l' },
			{ "quiet", 0, 0, 'q' },
			{ "start", 1, 0, 's' },
			{ "video", 0, 0, 'v' },
			{ "version", 0, 0, 'V'},
			{ "verbose", 0, 0, 'R'},
			{ "help", 0, 0, 'h'},
			{ NULL, 0, 0, 0 }
		};

		c = getopt_long_only(argc, argv, "ael:qs:vVh",
			long_options, &option_index);

		if (c == -1)
			break;

		switch (c) {
		case 'h':
		  fprintf(stderr, "%s - %s version %s\n", progName,
			  MPEG4IP_PACKAGE, MPEG4IP_VERSION);
		  fprintf(stderr, "options:\n");
		  fprintf(stderr, " --audio - extract audio track\n");
		  fprintf(stderr, " --length <length> - extract <length> secs\n");
		  fprintf(stderr, " --quiet - quiet mode\n");
		  fprintf(stderr, " --start <time> - extract from <start> time\n");
		  fprintf(stderr, " --video - extract video track\n");
		  fprintf(stderr, " --eliminate-short-frames <bytes> - eliminate short frames of bytes or less - default 4\n");
		  return 0;
		case 'a': {
			extractVideo = FALSE;
			break;
		}
		case 'e':
		  eliminate_short_frames = TRUE;
		  if (optarg) {
		    if (optarg[0] == '=') optarg[0] = ' ';
		    if (sscanf(optarg, "%u", &short_frames_len) != 1) {
		      fprintf(stderr, "%s:bad eliminate length %s\n",
			      progName, optarg);
		    }
		  } else {
		    short_frames_len = 4;
		  }
		  break;
		case 'l': {
			/* --length=<secs> */
			u_int i;
			if (sscanf(optarg, "%u", &i) < 1) {
				fprintf(stderr, 
					"%s: bad length specified: %s\n",
					 progName, optarg);
			} else {
				duration = i;
			}
			break;
		}
		case 'q': {
			quiet = TRUE;
			break;
		}
		case 's': {
			/* --start=<secs> */
			u_int i;
			if (sscanf(optarg, "%u", &i) < 1) {
				fprintf(stderr, 
					"%s: bad start specified: %s\n",
					 progName, optarg);
			} else {
				start = i;
			}
			break;
		}
		case 'v': {
			extractVideo = TRUE;
			break;
		}
		case '?':
			break;
		case 'R':
		  verbose = TRUE; quiet = FALSE;
		  break;
		case 'V':
		  fprintf(stderr, "%s - %s version %s\n", progName,
			  MPEG4IP_PACKAGE, MPEG4IP_VERSION);
		  return(0);
		default:
			fprintf(stderr, "%s: unknown option specified, ignoring: %c\n", 
				progName, c);
		}
	}

	/* check that we have at least two non-option arguments */
	if ((argc - optind) < 2) {
		fprintf(stderr, 
			"usage: %s <avi-file> <raw-file>\n",
			progName);
		exit(1);
	}

	/* point to the specified file names */
	aviFileName = argv[optind++];
	rawFileName = argv[optind++];

	/* warn about extraneous non-option arguments */
	if (optind < argc) {
		fprintf(stderr, "%s: unknown options specified, ignoring: ", progName);
		while (optind < argc) {
			fprintf(stderr, "%s ", argv[optind++]);
		}
		fprintf(stderr, "\n");
	}

	/* end processing of command line */

	/* open the AVI file */
	aviFile = AVI_open_input_file(aviFileName, TRUE);
	if (aviFile == NULL) {
		fprintf(stderr, 
			"%s: error %s: %s\n",
			progName, aviFileName, AVI_strerror());
		exit(4);
	}

	if (!quiet) {
	  fprintf(stderr, "%s - %s version %s\n",
		  progName, MPEG4IP_PACKAGE, MPEG4IP_VERSION);
	}
	/* open the RAW file */
	rawFile = fopen(rawFileName, "wb");
	if (rawFile == NULL) {
		fprintf(stderr,
			"%s: error opening %s: %s\n",
			progName, rawFileName, strerror(errno));
		exit(5);
	}

	if (extractVideo) {

		double videoFrameRate = AVI_video_frame_rate(aviFile);
		u_int32_t numVideoFrames = AVI_video_frames(aviFile);
		u_int32_t fileDuration = ceil(numVideoFrames / videoFrameRate);
		u_int32_t numDesiredVideoFrames;
		u_int32_t videoFramesRead = 0;
		u_int32_t emptyFramesRead = 0;
		/* get a buffer large enough to handle a frame of raw SDTV */
		u_char* buf = (u_char*)malloc(768 * 576 * 4);

		if (duration) {
			numDesiredVideoFrames = duration * videoFrameRate;
		} else {
			numDesiredVideoFrames = numVideoFrames;
		}

		if (buf == NULL) {
			fprintf(stderr,
				"%s: error allocating memory: %s\n",
				progName, strerror(errno));
			exit(6);
		}

		/* check that start offset is valid */
		if (start > fileDuration) {
			fprintf(stderr,
				"%s: specified start is past the end of the file\n",
				progName);
			exit(7);
		}

		if (AVI_seek_start(aviFile)) {
			fprintf(stderr,
				"%s: bad seek: %s\n",
				progName, AVI_strerror());
			exit(8);
		}
		if (AVI_set_video_position(aviFile, (long) ROUND(start * videoFrameRate), NULL)) {
			fprintf(stderr,
				"%s: bad seek: %s\n",
				progName, AVI_strerror());
			exit(9);
		}
#ifdef DEBUG_H264
		h264_decode_t dec;
#endif

		while (TRUE) {
		  numBytes = AVI_read_frame(aviFile, (char *)buf);

			/* read error */
			if (numBytes < 0) {
				break;
			}

			totBytes += numBytes;
			videoFramesRead++;
			if (verbose) {
			  printf("frame %d - len %u total %u\n", 
				 videoFramesRead, numBytes, totBytes);
			}
			/*
			 * note some capture programs 
			 * insert a zero length frame occasionally
			 * hence numBytes == 0, but we're not a EOF
			 */
			if ((eliminate_short_frames && numBytes > short_frames_len) ||
			    (eliminate_short_frames == FALSE && numBytes)) {
			  // test
#ifdef DEBUG_H264
			  uint32_t offset = 0, read;
			  do {
			    if (h264_is_start_code(buf + offset)) {
			      int ret = 
			      h264_detect_boundary(buf + offset, 
						   numBytes - offset, 
						   &dec);

			      printf(" frame offset %d nal type %d slice %d %d\n", 
				     offset,
				     dec.nal_unit_type,
				     dec.slice_type,
				     ret);
			    }
			    read = h264_find_next_start_code(buf + offset, 
							     numBytes - offset);
			    offset += read;
			  } while (read != 0 && offset < numBytes);
#endif
				if (fwrite(buf, 1, numBytes, rawFile) != numBytes) {
					fprintf(stderr,
						"%s: error writing %s: %s\n",
						progName, rawFileName, strerror(errno));
					break;
				}
			} else {
				emptyFramesRead++;
			}
			if (videoFramesRead >= numDesiredVideoFrames) {
				break;
			}
		}
		if (verbose) {
		  printf("read %u video bytes\n", totBytes);
		}

		if (numBytes < 0) {
			printf("%s: error reading %s, frame %d, %s\n",
				progName, aviFileName, videoFramesRead + 1, AVI_strerror());
		}
		if (videoFramesRead < numDesiredVideoFrames) {
			fprintf(stderr,
				"%s: warning: could only extract %u seconds of video (%u of %u frames)\n",
				progName, (unsigned int)ceil(videoFramesRead / videoFrameRate),
				videoFramesRead, numDesiredVideoFrames);
		}
		if (emptyFramesRead) {
			fprintf(stderr,
				"%s: warning: %u zero length frames ignored\n",
				progName, emptyFramesRead);
		}

		if (!quiet) {
			printf("%u video frames written\n", 
				videoFramesRead - emptyFramesRead);
		}

		/* cleanup */
		free(buf);

	} else {
		/* extract audio */
	  u_int32_t audioBytesRead = 0;
	  u_char *buf = (u_char*) malloc(8*1024);
	  u_int32_t numDesiredAudioBytes = AVI_audio_bytes(aviFile);
	  u_int32_t audioBytesPerSec = 0;
	  if (start != 0) {
		u_int32_t numAudioBytes = numDesiredAudioBytes;
		u_int32_t fileDuration;
		audioBytesPerSec = AVI_audio_rate(aviFile) * 	
		  ((AVI_audio_bits(aviFile) + 7) / 8) * AVI_audio_channels(aviFile);
		fileDuration = ceil(numAudioBytes / audioBytesPerSec);
		numDesiredAudioBytes = duration * audioBytesPerSec;

		/* check that start offset is valid */
		if (start > fileDuration) {
			fprintf(stderr,
				"%s: specified start is past the end of the file\n",
				progName);
			exit(7);
		}
		if (AVI_seek_start(aviFile)) {
			fprintf(stderr,
				"%s: bad seek: %s\n",
				progName, AVI_strerror());
			exit(8);
		}
		if (AVI_set_audio_position(aviFile, start * audioBytesPerSec)) {
			fprintf(stderr,
				"%s: bad seek: %s\n",
				progName, AVI_strerror());
			exit(9);
		}
	  } else {
		if (AVI_seek_start(aviFile)) {
			fprintf(stderr,
				"%s: bad seek: %s\n",
				progName, AVI_strerror());
			exit(8);
		}
		if (AVI_set_audio_position(aviFile, 0)) {
			fprintf(stderr,
				"%s: bad seek: %s\n",
				progName, AVI_strerror());
			exit(9);
		}
	  }

	  while ((numBytes = AVI_read_audio(aviFile, (char *)buf, sizeof(buf))) > 0) {
			if (fwrite(buf, 1, numBytes, rawFile) != numBytes) {
				fprintf(stderr,
					"%s: error writing %s: %s\n",
					progName, rawFileName, strerror(errno));
				break;
			}

			audioBytesRead += numBytes;
			if (numDesiredAudioBytes 
			  && audioBytesRead >= numDesiredAudioBytes) {
				break;
			}
		}

		if (verbose) {
		  printf("read %u audio bytes\n", audioBytesRead);
		}
		if (duration && audioBytesRead < numDesiredAudioBytes) {
			fprintf(stderr,
				"%s: warning: could only extract %u seconds of audio\n",
				progName, audioBytesPerSec == 0 ? audioBytesRead : audioBytesRead / audioBytesPerSec);
		}

		if (!quiet && AVI_audio_bits(aviFile) != 0) {
			printf("%u audio samples written\n", 
				audioBytesRead / ((AVI_audio_bits(aviFile) + 7) / 8)); 
		}

	}

	/* cleanup */
	AVI_close(aviFile);
	fclose(rawFile);

	return(0);
}
コード例 #3
0
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);
}