199 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 | 
						|
 *
 | 
						|
 *  Use of this source code is governed by a BSD-style license
 | 
						|
 *  that can be found in the LICENSE file in the root of the source
 | 
						|
 *  tree. An additional intellectual property rights grant can be found
 | 
						|
 *  in the file PATENTS.  All contributing project authors may
 | 
						|
 *  be found in the AUTHORS file in the root of the source tree.
 | 
						|
 */
 | 
						|
 | 
						|
#include "./webmdec.h"
 | 
						|
 | 
						|
#include <stdarg.h>
 | 
						|
 | 
						|
#include "third_party/nestegg/include/nestegg/nestegg.h"
 | 
						|
 | 
						|
static int nestegg_read_cb(void *buffer, size_t length, void *userdata) {
 | 
						|
  FILE *f = userdata;
 | 
						|
 | 
						|
  if (fread(buffer, 1, length, f) < length) {
 | 
						|
    if (ferror(f))
 | 
						|
      return -1;
 | 
						|
    if (feof(f))
 | 
						|
      return 0;
 | 
						|
  }
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
static int nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
 | 
						|
  switch (whence) {
 | 
						|
    case NESTEGG_SEEK_SET:
 | 
						|
      whence = SEEK_SET;
 | 
						|
      break;
 | 
						|
    case NESTEGG_SEEK_CUR:
 | 
						|
      whence = SEEK_CUR;
 | 
						|
      break;
 | 
						|
    case NESTEGG_SEEK_END:
 | 
						|
      whence = SEEK_END;
 | 
						|
      break;
 | 
						|
  };
 | 
						|
  return fseek(userdata, (int32_t)offset, whence) ? -1 : 0;
 | 
						|
}
 | 
						|
 | 
						|
static int64_t nestegg_tell_cb(void *userdata) {
 | 
						|
  return ftell(userdata);
 | 
						|
}
 | 
						|
 | 
						|
static void nestegg_log_cb(nestegg *context,
 | 
						|
                           unsigned int severity,
 | 
						|
                           char const *format, ...) {
 | 
						|
  va_list ap;
 | 
						|
  va_start(ap, format);
 | 
						|
  vfprintf(stderr, format, ap);
 | 
						|
  fprintf(stderr, "\n");
 | 
						|
  va_end(ap);
 | 
						|
}
 | 
						|
 | 
						|
int file_is_webm(struct WebmInputContext *webm_ctx,
 | 
						|
                 struct VpxInputContext *vpx_ctx) {
 | 
						|
  uint32_t i, n;
 | 
						|
  int track_type = -1;
 | 
						|
  int codec_id;
 | 
						|
 | 
						|
  nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
 | 
						|
  nestegg_video_params params;
 | 
						|
 | 
						|
  io.userdata = vpx_ctx->file;
 | 
						|
  if (nestegg_init(&webm_ctx->nestegg_ctx, io, NULL, -1))
 | 
						|
    goto fail;
 | 
						|
 | 
						|
  if (nestegg_track_count(webm_ctx->nestegg_ctx, &n))
 | 
						|
    goto fail;
 | 
						|
 | 
						|
  for (i = 0; i < n; i++) {
 | 
						|
    track_type = nestegg_track_type(webm_ctx->nestegg_ctx, i);
 | 
						|
 | 
						|
    if (track_type == NESTEGG_TRACK_VIDEO)
 | 
						|
      break;
 | 
						|
    else if (track_type < 0)
 | 
						|
      goto fail;
 | 
						|
  }
 | 
						|
 | 
						|
  codec_id = nestegg_track_codec_id(webm_ctx->nestegg_ctx, i);
 | 
						|
  if (codec_id == NESTEGG_CODEC_VP8) {
 | 
						|
    vpx_ctx->fourcc = VP8_FOURCC;
 | 
						|
  } else if (codec_id == NESTEGG_CODEC_VP9) {
 | 
						|
    vpx_ctx->fourcc = VP9_FOURCC;
 | 
						|
  } else {
 | 
						|
    fatal("Not VPx video, quitting.\n");
 | 
						|
  }
 | 
						|
 | 
						|
  webm_ctx->video_track = i;
 | 
						|
 | 
						|
  if (nestegg_track_video_params(webm_ctx->nestegg_ctx, i, ¶ms))
 | 
						|
    goto fail;
 | 
						|
 | 
						|
  vpx_ctx->framerate.denominator = 0;
 | 
						|
  vpx_ctx->framerate.numerator = 0;
 | 
						|
  vpx_ctx->width = params.width;
 | 
						|
  vpx_ctx->height = params.height;
 | 
						|
 | 
						|
  return 1;
 | 
						|
 | 
						|
 fail:
 | 
						|
  webm_ctx->nestegg_ctx = NULL;
 | 
						|
  rewind(vpx_ctx->file);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int webm_read_frame(struct WebmInputContext *webm_ctx,
 | 
						|
                    uint8_t **buffer,
 | 
						|
                    size_t *bytes_in_buffer,
 | 
						|
                    size_t *buffer_size) {
 | 
						|
  if (webm_ctx->chunk >= webm_ctx->chunks) {
 | 
						|
    uint32_t track;
 | 
						|
 | 
						|
    do {
 | 
						|
      /* End of this packet, get another. */
 | 
						|
      if (webm_ctx->pkt) {
 | 
						|
        nestegg_free_packet(webm_ctx->pkt);
 | 
						|
        webm_ctx->pkt = NULL;
 | 
						|
      }
 | 
						|
 | 
						|
      if (nestegg_read_packet(webm_ctx->nestegg_ctx, &webm_ctx->pkt) <= 0 ||
 | 
						|
          nestegg_packet_track(webm_ctx->pkt, &track)) {
 | 
						|
        return 1;
 | 
						|
      }
 | 
						|
    } while (track != webm_ctx->video_track);
 | 
						|
 | 
						|
    if (nestegg_packet_count(webm_ctx->pkt, &webm_ctx->chunks))
 | 
						|
      return 1;
 | 
						|
 | 
						|
    webm_ctx->chunk = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (nestegg_packet_data(webm_ctx->pkt, webm_ctx->chunk,
 | 
						|
                          buffer, bytes_in_buffer)) {
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  webm_ctx->chunk++;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int webm_guess_framerate(struct WebmInputContext *webm_ctx,
 | 
						|
                         struct VpxInputContext *vpx_ctx) {
 | 
						|
  uint32_t i;
 | 
						|
  uint64_t tstamp = 0;
 | 
						|
 | 
						|
  /* Check to see if we can seek before we parse any data. */
 | 
						|
  if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0)) {
 | 
						|
    warn("Failed to guess framerate (no Cues), set to 30fps.\n");
 | 
						|
    vpx_ctx->framerate.numerator = 30;
 | 
						|
    vpx_ctx->framerate.denominator  = 1;
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Guess the framerate. Read up to 1 second, or 50 video packets,
 | 
						|
   * whichever comes first.
 | 
						|
   */
 | 
						|
  for (i = 0; tstamp < 1000000000 && i < 50;) {
 | 
						|
    nestegg_packet *pkt;
 | 
						|
    uint32_t track;
 | 
						|
 | 
						|
    if (nestegg_read_packet(webm_ctx->nestegg_ctx, &pkt) <= 0)
 | 
						|
      break;
 | 
						|
 | 
						|
    nestegg_packet_track(pkt, &track);
 | 
						|
    if (track == webm_ctx->video_track) {
 | 
						|
      nestegg_packet_tstamp(pkt, &tstamp);
 | 
						|
      ++i;
 | 
						|
    }
 | 
						|
 | 
						|
    nestegg_free_packet(pkt);
 | 
						|
  }
 | 
						|
 | 
						|
  if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0))
 | 
						|
    goto fail;
 | 
						|
 | 
						|
  vpx_ctx->framerate.numerator = (i - 1) * 1000000;
 | 
						|
  vpx_ctx->framerate.denominator = (int)(tstamp / 1000);
 | 
						|
  return 0;
 | 
						|
 | 
						|
 fail:
 | 
						|
  nestegg_destroy(webm_ctx->nestegg_ctx);
 | 
						|
  webm_ctx->nestegg_ctx = NULL;
 | 
						|
  rewind(vpx_ctx->file);
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
void webm_free(struct WebmInputContext *webm_ctx) {
 | 
						|
  if (webm_ctx && webm_ctx->nestegg_ctx) {
 | 
						|
    if (webm_ctx->pkt)
 | 
						|
      nestegg_free_packet(webm_ctx->pkt);
 | 
						|
    nestegg_destroy(webm_ctx->nestegg_ctx);
 | 
						|
  }
 | 
						|
}
 |