⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpeg3vtrack.c

📁 MPEG-4编解码的实现(包括MPEG4视音频编解码)
💻 C
字号:
#include "libmpeg3.h"
#include "mpeg3private.h"
#include "mpeg3protos.h"
#include "mpeg3vtrack.h"
#include "video/mpeg3video.h"
#include "video/mpeg3videoprotos.h"
#include "mp4av.h"
#include <stdlib.h>

void mpeg3vtrack_cleanup_frame (mpeg3_vtrack_t *track)
{
  long size;

  if (track->track_frame_buffer == NULL) return;

  size = track->track_frame_buffer_size;
  track->track_frame_buffer[0] = track->track_frame_buffer[size - 4];
  track->track_frame_buffer[1] = track->track_frame_buffer[size - 3];
  track->track_frame_buffer[2] = track->track_frame_buffer[size - 2];
  track->track_frame_buffer[3] = track->track_frame_buffer[size - 1];
#if 0
  printf("Clean up - code is %x %x %x %x\n",
	 track->track_frame_buffer[0],
	 track->track_frame_buffer[1],
	 track->track_frame_buffer[2],
	 track->track_frame_buffer[3]);
#endif
  track->track_frame_buffer_size = 4;
}

static 
int mpeg3vtrack_locate_frame (mpeg3_vtrack_t *track,
			    long frame)
{
  mpeg3_demuxer_t *demux;
  long start_frame;
  uint32_t offset;
  uint32_t code = 0;
  demux = track->demuxer;
  if (frame < track->current_position) {
    mpeg3demux_seek_start(demux);
    start_frame = 0;
  } else
    start_frame = track->current_position;

  // clean out last frame
  while (!mpeg3demux_eof(demux)) {
    mpeg3vtrack_cleanup_frame(track);
    offset = 4;
    track->track_frame_buffer_size = 
    mpeg3demux_read_data(demux,
			 track->track_frame_buffer,
			 track->track_frame_buffer_maxsize);
    for (offset = 4, code = 0; offset < track->track_frame_buffer_size - 3; offset++) {
      code <<= 8;
      code |= track->track_frame_buffer[offset];
      if (code == MPEG3_PICTURE_START_CODE) {
	start_frame++;
	if (start_frame >= frame) {
	  for (offset = offset - 3; 
	       offset < track->track_frame_buffer_size; 
	       offset++) {
	    mpeg3demux_read_prev_char(demux);
	  }
	  track->track_frame_buffer_size = 0;
	  track->current_position = frame;
	  return 0;
	}
      }
    }
  }
  return 1;
}
  
  
    
static
int mpeg3vtrack_get_frame (mpeg3_vtrack_t *track)

{
	u_int32_t code = 0;
	int have_pict_start, done;
	mpeg3_demuxer_t *demux = track->demuxer;
	unsigned char *output;

	have_pict_start = 0;
	track->current_position++;
	output = track->track_frame_buffer;
	if ((track->track_frame_buffer_size != 0) &&
	    output[0] == 0 && output[1] == 0 && output[2] == 1) {
	  if (output[3] == 0)
	      have_pict_start = 1;
	    output += 4;
	} 

	done = 0;
	while(done == 0 && 
		code != MPEG3_SEQUENCE_END_CODE &&
		!mpeg3demux_eof(demux))
	{
	  if (track->track_frame_buffer_size + 3 >= 
	      track->track_frame_buffer_maxsize) {
	    int diff = output - track->track_frame_buffer;
	    track->track_frame_buffer_maxsize += 4096;
	    track->track_frame_buffer = 
	      realloc(track->track_frame_buffer, 
		      track->track_frame_buffer_maxsize);
	    if (track->track_frame_buffer == NULL) exit(1);
	    output = track->track_frame_buffer + diff;
	  }
	  

	  code <<= 8;
	  // can't do this yet - we're still reading from the demuxer...
	  *output = mpeg3demux_read_char(track->demuxer);
	  code |= *output++;
	  //	  printf("%d %08x\n", track->track_frame_buffer_size, code);
	  track->track_frame_buffer_size++;
	  if (code == MPEG3_PICTURE_START_CODE) {
	    if (have_pict_start == 1) done = 1;
	    have_pict_start = 1;
	  } else if ((code == MPEG3_GOP_START_CODE) ||
		     (code == MPEG3_SEQUENCE_START_CODE)) {
	    if (have_pict_start == 1) done = 1;
	  }
	}
	return mpeg3demux_eof(demux);
}



/* Line up on the beginning of the previous code. */
int mpeg3vtrack_prev_code(mpeg3_demuxer_t* demux, uint32_t code)
{
  uint32_t testcode = 0;
  int bytes = 0;

  if (mpeg3demux_bof(demux)) return mpeg3demux_bof(demux);

  do {
    testcode >>= 8;
    testcode |= (mpeg3demux_read_prev_char(demux) << 24);
    bytes++;
  } while(!mpeg3demux_bof(demux) && testcode != code);

  return mpeg3demux_bof(demux);
}

// Must perform seeking now to get timecode for audio
int mpeg3vtrack_seek_percentage(mpeg3_vtrack_t *vtrack, double percentage)
{
  vtrack->percentage_seek = percentage;
  return 0;
}

int mpeg3vtrack_seek_frame(mpeg3_vtrack_t *vtrack, long frame)
{
  vtrack->frame_seek = frame;
  return 0;
}

int mpeg3vtrack_seek(mpeg3_vtrack_t *track, int dont_decode)
{
  long this_gop_start;
  int result = 0;
  int back_step;
  int attempts;
  mpeg3_t *file = track->file;
  int is_video_stream = file->is_video_stream;
  double percentage;
  long frame_number;
  int match_refframes = 1;
  mpeg3_demuxer_t *demux = track->demuxer;
  int ix;


  // Must do seeking here so files which don't use video don't seek.
  /* Seek to percentage */
  if(track->percentage_seek >= 0)
    {
      //printf("mpeg3video_seek 1 %f\n", video->percentage_seek);
      track->track_frame_buffer_size = 0;

      percentage = track->percentage_seek;
      track->percentage_seek = -1;
      mpeg3demux_seek_percentage(track->demuxer, percentage);
      printf("Seek time is %g\n", mpeg3demux_get_time(track->demuxer));
    }
  else
    /* Seek to a frame */
    if(track->frame_seek >= 0)
      {
	frame_number = track->frame_seek;
	track->frame_seek = -1;
	if(frame_number < 0) frame_number = 0;
	if(frame_number > track->total_frames) 
	  frame_number = track->total_frames;

	//printf("mpeg3video_seek 1 %ld %ld\n", frame_number, video->framenum);

	/* Seek to I frame in table of contents */
	if(track->frame_offsets)
	  {
	    int i;
	    for(i = track->total_keyframe_numbers - 1; i >= 0; i--)
	      {
		if(track->keyframe_numbers[i] <= frame_number)
		  {
		    int frame;
		    int title_number;
		    int64_t byte;

		    // Go 2 I-frames before current position
		    frame = track->keyframe_numbers[i];
		    title_number = (track->frame_offsets[frame] & 
				    0xff00000000000000) >> 56;
		    byte = track->frame_offsets[frame] & 
		      0xffffffffffffff;


		    mpeg3demux_open_title(demux, title_number);
		    mpeg3demux_seek_byte(demux, byte);

		    for (ix = frame; ix < frame_number; ix++) {
		      mpeg3vtrack_get_frame(track);
		    }
		    break;
		  }
	      }
	  }
	else
	  /* Seek to start of file */
	  {
	  if(frame_number < 16)
	    {
	      mpeg3demux_seek_start(demux);
	      for (ix = 0; ix < frame_number; ix++) {
		mpeg3vtrack_get_frame(track);
	      }
#if 0
	      track->video->repeat_count = track->video->current_repeat = 0;
	      track->video->framenum = 0;
	      result = mpeg3vtrack_drop_frames(track, 
					       frame_number - video->framenum);
#endif
	    }
	  else
	    {
	      /* Seek to an I frame. */
		  /* Elementary stream */
		  if(is_video_stream)
		    {
#if 0
		      //mpeg3_t *file = video->file;
		      mpeg3_vtrack_t *track = video->track;
		      int64_t byte = (int64_t)((double)(mpeg3demuxer_total_bytes(vstream->demuxer) / 
							track->total_frames) * 
					       frame_number);
		      long minimum = 65535;
		      int done = 0;

		      //printf("seek elementary %d\n", frame_number);
		      /* Get GOP just before frame */
		      do
			{
			  result = mpeg3demux_seek_byte(demux, byte);

			  if(!result) 
			    result = mpeg3vtrack_prev_code(demux, MPEG3_GOP_START_CODE);
			  mpeg3demux_read_char(demux);
			  if(!result) result = mpeg3video_getgophdr(video);
			  this_gop_start = mpeg3video_goptimecode_to_frame(video);

			  //printf("wanted %ld guessed %ld byte %ld result %d\n", frame_number, this_gop_start, byte, result);
			  if(labs(this_gop_start - frame_number) >= labs(minimum)) 
			    done = 1;
			  else
			    {
			      minimum = this_gop_start - frame_number;
			      byte += (long)((float)(frame_number - this_gop_start) * 
					     (float)(mpeg3demuxer_total_bytes(vstream->demuxer) / 
						     track->total_frames));
			      if(byte < 0) byte = 0;
			    }
			}while(!result && !done);

		      //printf("wanted %d guessed %d\n", frame_number, this_gop_start);
		      if(!result)
			{
			  video->framenum = this_gop_start;
			  result = mpeg3video_drop_frames(video, frame_number - video->framenum);
			}
#endif
		    }
		  else



		    /* System stream */
		    {
		      mpeg3vtrack_locate_frame(track, frame_number);
#if 0
		      mpeg3demux_seek_time(demux, ((double)frame_number) / track->frame_rate);
		      percentage = mpeg3demux_tell_percentage(demux);
#endif
		      //printf("seek frame %ld percentage %f byte %ld\n", frame_number, percentage, mpeg3bits_tell(vstream));
		    }
		}

	    }
      }

  return result;
}

int mpeg3vtrack_previous_frame(mpeg3_vtrack_t *vtrack)
{
  int ix;
  if(mpeg3demux_tell_percentage(vtrack->demuxer) <= 0) return 1;

  // Get one picture
  mpeg3vtrack_prev_code(vtrack->demuxer, MPEG3_PICTURE_START_CODE);
  for (ix = 0; ix < 4; ix++) {
    mpeg3demux_read_prev_char(vtrack->demuxer);
  }

  if(mpeg3demux_bof(vtrack->demuxer)) 
    mpeg3demux_seek_percentage(vtrack->demuxer, 0);
  //  vtrack->video->repeat_count = 0;
  return 0;
}

#if 0
int mpeg3vtrack_drop_frames(mpeg3_vtrack_t *vtrack, long frames)
{
  int result = 0;
  long frame_number = video->framenum + frames;

  /* Read the selected number of frames and skip b-frames */
  while(!result && frame_number > video->framenum)
    {
      result = mpeg3video_read_frame_backend(video, frame_number - video->framenum);
    }
  return result;
}
#endif
/* ======================================================================= */
/*                                    ENTRY POINTS */
/* ======================================================================= */


mpeg3_vtrack_t* mpeg3_new_vtrack(mpeg3_t *file, 
	int stream_id, 
	mpeg3_demuxer_t *demuxer,
	int number)
{
  uint32_t h,w;
  double frame_rate;

	int result = 0;
	mpeg3_vtrack_t *new_vtrack;
	new_vtrack = calloc(1, sizeof(mpeg3_vtrack_t));
	new_vtrack->file = file;
	new_vtrack->demuxer = mpeg3_new_demuxer(file, 0, 1, stream_id);
	if(new_vtrack->demuxer) mpeg3demux_copy_titles(new_vtrack->demuxer, demuxer);
	new_vtrack->current_position = 0;
	new_vtrack->percentage_seek = -1;
	new_vtrack->frame_seek = -1;
	new_vtrack->track_frame_buffer = NULL;
	new_vtrack->track_frame_buffer_maxsize = 0;

//printf("mpeg3_new_vtrack 1\n");
// Copy pointers
	if(file->frame_offsets)
	{
		new_vtrack->frame_offsets = file->frame_offsets[number];
		new_vtrack->total_frame_offsets = file->total_frame_offsets[number];
		new_vtrack->keyframe_numbers = file->keyframe_numbers[number];
		new_vtrack->total_keyframe_numbers = file->total_keyframe_numbers[number];
	}

//printf("mpeg3_new_vtrack 1\n");
//printf("mpeg3_new_vtrack %llx\n", mpeg3demux_tell(new_vtrack->demuxer));
/* Get information about the track here. */

	if (mpeg3vtrack_get_frame(new_vtrack)) {
	  mpeg3_delete_vtrack(file, new_vtrack);
	  return NULL;
	}
	
	if (MP4AV_Mpeg3ParseSeqHdr(new_vtrack->track_frame_buffer, 
				   new_vtrack->track_frame_buffer_size, 
				   &h,
				   &w, 
				   &frame_rate) < 0) {
	  mpeg3_delete_vtrack(file, new_vtrack);
	  return NULL;
	}

	new_vtrack->frame_rate = frame_rate;
	new_vtrack->width = w;
	new_vtrack->height = h;
	mpeg3demux_seek_start(new_vtrack->demuxer);
	new_vtrack->track_frame_buffer_size = 0;

	if (!new_vtrack->frame_offsets) {
	  if (file->is_video_stream) {
	  } else {
	    new_vtrack->total_frames = 
	      (long)(mpeg3demux_length(new_vtrack->demuxer) * frame_rate);
	  }
	} else {
	  new_vtrack->total_frames = new_vtrack->total_frame_offsets;
	}

//printf("mpeg3_new_vtrack 2\n");
	return new_vtrack;
}

int mpeg3_delete_vtrack(mpeg3_t *file, mpeg3_vtrack_t *vtrack)
{
	if(vtrack->demuxer) mpeg3_delete_demuxer(vtrack->demuxer);
	free(vtrack);
	return 0;
}

/* Read all the way up to and including the next picture start code */
int mpeg3vtrack_read_raw (mpeg3_vtrack_t *vtrack, 
			  unsigned char *output, 
			  long *size, 
			  long max_size)
{
  u_int32_t code = 0;

  mpeg3_demuxer_t *demux = vtrack->demuxer;
  *size = 0;
  while(code != MPEG3_PICTURE_START_CODE && 
	code != MPEG3_SEQUENCE_END_CODE &&
	*size < max_size && 
	!mpeg3demux_eof(demux))
    {
      code <<= 8;
      *output = mpeg3demux_read_char(demux);
      code |= *output++;
      (*size)++;
    }
  return mpeg3demux_eof(demux);
}
/* Read all the way up to and including the next picture start code */
int mpeg3vtrack_read_raw_resize (mpeg3_vtrack_t *vtrack, 
				 unsigned char **optr, 
				 long *size, 
				 int first)
{
  int result = 0;

  result = mpeg3vtrack_seek(vtrack, 1);
  
  if (!result) result = mpeg3vtrack_get_frame(vtrack);

  if (!result) {
    *optr = vtrack->track_frame_buffer;
    *size = vtrack->track_frame_buffer_size;
  }
  return result;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -