Example #1
0
static bool ffmpeg_find_h264_size (ffmpeg_codec_t *ffmpeg,
                                   const uint8_t *ud,
                                   uint32_t ud_size)
{
    uint32_t offset = 0;
    do {
        if (h264_is_start_code(ud + offset)) {
            if (h264_nal_unit_type(ud + offset) == H264_NAL_TYPE_SEQ_PARAM) {
                h264_decode_t dec;
                memset(&dec, 0, sizeof(dec));
                if (h264_read_seq_info(ud + offset, ud_size - offset, &dec) == 0) {
                    ffmpeg->m_c->width = dec.pic_width;
                    ffmpeg->m_c->height = dec.pic_height;
                    return true;
                }
            }
        }
        offset += h264_find_next_start_code(ud + offset, ud_size - offset);
    } while (offset < ud_size);
    return false;
}
Example #2
0
bool CX264VideoEncoder::GetEsConfig (uint8_t **ppEsConfig, 
				     uint32_t *pEsConfigLen)
{
#ifdef DEBUG_H264
  debug_message("Getting es config for x264");
#endif
  CHECK_AND_FREE(Profile()->m_videoMpeg4Config);
  Profile()->m_videoMpeg4ConfigLength = 0;

  x264_nal_t *nal;
  int nal_num;
  if (x264_encoder_headers(m_h, &nal, &nal_num) != 0) {
    error_message("x264 - can't create headers");
    StopEncoder();
    return false;
  }
  
  uint8_t *seqptr = m_vopBuffer;
  uint8_t *picptr = m_vopBuffer;
  uint32_t seqlen = 0, piclen = 0;
  bool found_seq = false, found_pic = false;
  if (m_vopBuffer == NULL) {
    m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize);
  }
  uint8_t *vopBuffer = m_vopBuffer;
  int vopBufferLen = Profile()->m_videoMaxVopSize;

  for (int ix = 0; ix < nal_num; ix++) {
    int i_size;
    i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]);
    if (i_size > 0) {
      bool useit = false;
      uint header_size = 0;
      if (h264_is_start_code(vopBuffer)) {
	header_size = vopBuffer[2] == 1 ? 3 : 4;
      }
      if (nal[ix].i_type == H264_NAL_TYPE_SEQ_PARAM) {
	found_seq = true;
	seqlen = i_size - header_size;
	seqptr = vopBuffer + header_size;
	useit = true;
      } else if (nal[ix].i_type == H264_NAL_TYPE_PIC_PARAM) {
	found_pic = true;
	piclen = i_size - header_size;
	picptr = vopBuffer + header_size;
	useit = true;
      }
      if (useit) {
	vopBuffer += i_size;
	vopBufferLen -= i_size;
      }
    }
  }
	  
  if (found_seq == false) {
    error_message("Can't find seq pointer in x264 header");
    StopEncoder();
    return false;
  }
  if (found_pic == false) {
    error_message("Can't find pic pointer in x264 header");
    StopEncoder();
    return false;
  }

  uint8_t *p = seqptr;
  
  if (*p == 0 && p[1] == 0 && 
      (p[2] == 1 || (p[2] == 0 && p[3] == 1))) {
    if (p[2] == 0) p += 4;
    else p += 3;
  }
  Profile()->m_videoMpeg4ProfileId = p[1] << 16 |
    p[2] << 8 |
    p[3];

  debug_message("profile id %x", Profile()->m_videoMpeg4ProfileId);
  
  char *sprop = NULL;
  char *base64;
  base64 = MP4BinaryToBase64(seqptr, seqlen);
  sprop = strdup(base64);
  free(base64);
  base64 = MP4BinaryToBase64(picptr, piclen);
  sprop = (char *)realloc(sprop, strlen(sprop) + strlen(base64) + 1 + 1);
  strcat(sprop, ",");
  strcat(sprop, base64);
  free(base64);

  debug_message("sprop %s", sprop);
  Profile()->m_videoMpeg4Config = (uint8_t *)sprop;
  Profile()->m_videoMpeg4ConfigLength = strlen(sprop) + 1;
  StopEncoder();
  return true;
}
Example #3
0
bool CX264VideoEncoder::EncodeImage(
				      const u_int8_t* pY, 
				      const u_int8_t* pU, 
				      const u_int8_t* pV, 
	u_int32_t yStride, u_int32_t uvStride,
	bool wantKeyFrame, 
	Duration elapsedDuration,
	Timestamp srcFrameTimestamp)
{
  //debug_message("encoding at "U64, srcFrameTimestamp);
  m_push->Push(srcFrameTimestamp);
  if (m_vopBuffer == NULL) {
    m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize);
    if (m_vopBuffer == NULL) {
      error_message("Cannot malloc vop size");
      return false;
    }
  }
  m_count++;
  if (m_count >= m_key_frame_count) {
    wantKeyFrame = true;
    m_count = 0;
  }
#ifdef USE_OUR_YUV
  m_pic_input.img.plane[0] = (uint8_t *)pY;
  m_pic_input.img.i_stride[0] = yStride;
  m_pic_input.img.plane[1] = (uint8_t *)pU;
  m_pic_input.img.i_stride[1] = uvStride;
  m_pic_input.img.plane[2] = (uint8_t *)pV;
  m_pic_input.img.i_stride[2] = uvStride;
#else
  CopyYuv(pY, pU, pV, yStride, uvStride, uvStride,
	  m_pic_input.img.plane[0],m_pic_input.img.plane[1],m_pic_input.img.plane[2], 
	  m_pic_input.img.i_stride[0],m_pic_input.img.i_stride[1],m_pic_input.img.i_stride[2],
	  Profile()->m_videoWidth, Profile()->m_videoHeight);
#endif

  m_pic_input.i_type = wantKeyFrame ? X264_TYPE_IDR : X264_TYPE_AUTO;
  m_pic_input.i_pts = srcFrameTimestamp;

  x264_nal_t *nal;
  int i_nal;
  if (x264_encoder_encode(m_h, &nal, &i_nal, &m_pic_input, &m_pic_output) < 0) {
    error_message("x264_encoder_encode failed");
    return false;
  }
  CHECK_AND_FREE(m_nal_info);
  m_nal_info = (h264_nal_buf_t *)malloc(i_nal * sizeof(h264_nal_buf_t));
  uint8_t *vopBuffer = m_vopBuffer;
  int vopBufferLen = m_vopBufferLength;
  uint32_t loaded = 0;
  uint32_t nal_on = 0;

  // read the nals out of the encoder.  Nice...
  for (int ix = 0; ix < i_nal; ix++) {
    int i_size;
    bool skip = false;
    i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]);
    if (i_size > 0) {
      m_nal_info[nal_on].nal_length = i_size;
      m_nal_info[nal_on].nal_offset = loaded;
      m_nal_info[nal_on].nal_type = nal[ix].i_type;
      m_nal_info[nal_on].unique = false;
      uint32_t header = 0;
      if (h264_is_start_code(vopBuffer)) {
	header = vopBuffer[2] == 1 ? 3 : 4;
      }
      m_nal_info[nal_on].nal_length -= header;
      m_nal_info[nal_on].nal_offset += header;
      // we will send picture or sequence header through - let the
      // sinks decide to send or not
      if (skip == false) {
#ifdef DEBUG_H264
	uint8_t nal_type = nal[ix].i_type;
	if (h264_nal_unit_type_is_slice(nal_type)) {
	  uint8_t stype;
	  h264_find_slice_type(vopBuffer, i_size, &stype, true);
	  debug_message("nal %d - type %u slice type %u %d",
			ix, nal_type, stype, i_size);
	} else {
	  debug_message("nal %d - type %u %d", ix, nal_type, i_size);
	}
#endif
	nal_on++;
	loaded += i_size;
	vopBufferLen -= i_size;
	vopBuffer += i_size;
      } else {
#ifdef DEBUG_H264
	debug_message("skipped nal %u", nal[ix].i_type);
#endif
      }
    } else {
      error_message("Need to increase vop buffer size by %d", 
		    -i_size);
    }
  }
  m_nal_num = nal_on;
  m_vopBufferLength = loaded;
#ifdef DEBUG_H264
  debug_message("x264 loaded %d nals, %u len", 
		i_nal, loaded);
#endif
#ifdef OUTPUT_RAW
  if (m_vopBufferLength) {
    fwrite(m_vopBuffer, m_vopBufferLength, 1, m_outfile);
  }
#endif
	
  return true;
}
Example #4
0
/*
 * 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);
}