ref: c2b336815dddcd9fab2d4fb8ee199b816ce8c347
parent: 58b9c9fbce267894b69d4521bf34349f4e557b9b
author: Dmitry Kovalev <[email protected]>
date: Fri Jan 24 06:20:09 EST 2014
Implementing simple API to read video files. New API is supposed to be used from example code. Current implementation only supports IVF containers (will be extended to Y4M). Change-Id: Ib7da87237690b1a28297bdf03bc41c6836a84b7e
--- a/examples.mk
+++ b/examples.mk
@@ -76,9 +76,11 @@
postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7
postproc.DESCRIPTION = Decoder postprocessor control
GEN_EXAMPLES-$(CONFIG_VP8_DECODER) += decode_to_md5.c
-decode_to_md5.SRCS += md5_utils.h md5_utils.c
-decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42
-decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum
+decode_to_md5.SRCS += md5_utils.h md5_utils.c
+decode_to_md5.SRCS += ivfdec.h ivfdec.c
+decode_to_md5.SRCS += tools_common.h tools_common.c
+decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42
+decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum
GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += simple_encoder.c
simple_encoder.GUID = 4607D299-8A71-4D2C-9B1D-071899B6FBFD
--- a/examples/decode_to_md5.c
+++ b/examples/decode_to_md5.c
@@ -33,18 +33,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
#define VPX_CODEC_DISABLE_COMPAT 1
-#include "./vpx_config.h"
+
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
-#include "md5_utils.h"
+#include "./ivfdec.h"
+#include "./md5_utils.h"
+#include "./tools_common.h"
+#include "./vpx_config.h"
+
#define VP8_FOURCC 0x30385056
#define VP9_FOURCC 0x30395056
-#define IVF_FILE_HDR_SZ (32)
-#define IVF_FRAME_HDR_SZ (12)
-
static vpx_codec_iface_t *get_codec_interface(unsigned int fourcc) {
switch (fourcc) {
case VP8_FOURCC:
@@ -55,20 +57,6 @@
return NULL;
}
-static unsigned int mem_get_le32(const unsigned char *mem) {
- return (mem[3] << 24) | (mem[2] << 16) | (mem[1] << 8) | (mem[0]);
-}
-
-static void die(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- vprintf(fmt, ap);
- if (fmt[strlen(fmt) - 1] != '\n')
- printf("\n");
- exit(EXIT_FAILURE);
-}
-
static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
const char *detail = vpx_codec_error_detail(ctx);
@@ -106,17 +94,24 @@
fprintf(stream, "%02x", digest[i]);
}
+static const char *exec_name;
+
+void usage_exit() {
+ fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name);
+ exit(EXIT_FAILURE);
+}
+
int main(int argc, char **argv) {
FILE *infile, *outfile;
vpx_codec_ctx_t codec;
vpx_codec_iface_t *iface;
int flags = 0, frame_cnt = 0;
- unsigned char file_hdr[IVF_FILE_HDR_SZ];
- unsigned char frame_hdr[IVF_FRAME_HDR_SZ];
- unsigned char frame[256 * 1024];
+ vpx_video_t *video;
+ exec_name = argv[0];
+
if (argc != 3)
- die("Usage: %s <infile> <outfile>\n", argv[0]);
+ die("Invalid number of arguments");
if (!(infile = fopen(argv[1], "rb")))
die("Failed to open %s for reading", argv[1]);
@@ -124,32 +119,24 @@
if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing", argv[2]);
- if (!(fread(file_hdr, 1, IVF_FILE_HDR_SZ, infile) == IVF_FILE_HDR_SZ &&
- file_hdr[0] == 'D' && file_hdr[1] == 'K' &&
- file_hdr[2] == 'I' && file_hdr[3] == 'F'))
+ video = vpx_video_open_file(infile);
+ if (!video)
die("%s is not an IVF file.", argv[1]);
- iface = get_codec_interface(mem_get_le32(file_hdr + 8));
+ iface = get_codec_interface(vpx_video_get_fourcc(video));
if (!iface)
die("Unknown FOURCC code.");
-
printf("Using %s\n", vpx_codec_iface_name(iface));
if (vpx_codec_dec_init(&codec, iface, NULL, flags))
die_codec(&codec, "Failed to initialize decoder");
- while (fread(frame_hdr, 1, IVF_FRAME_HDR_SZ, infile) == IVF_FRAME_HDR_SZ) {
- const int frame_size = mem_get_le32(frame_hdr);
+ while (vpx_video_read_frame(video)) {
vpx_codec_iter_t iter = NULL;
- vpx_image_t *img;
-
- if (frame_size > sizeof(frame))
- die("Frame %d data too big for example code buffer", frame_size);
-
- if (fread(frame, 1, frame_size, infile) != frame_size)
- die("Failed to read complete frame");
-
+ vpx_image_t *img = NULL;
+ size_t frame_size = 0;
+ const unsigned char *frame = vpx_video_get_frame(video, &frame_size);
if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0))
die_codec(&codec, "Failed to decode frame");
@@ -166,6 +153,8 @@
printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec");
+
+ vpx_video_close(video);
fclose(outfile);
fclose(infile);
--- a/ivfdec.c
+++ b/ivfdec.c
@@ -8,11 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "./ivfdec.h"
-
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include "./ivfdec.h"
+
+static const char *IVF_SIGNATURE = "DKIF";
+
static void fix_framerate(int *num, int *den) {
// Some versions of vpxenc used 1/(2*fps) for the timebase, so
// we can guess the framerate using only the timebase in this
@@ -37,8 +40,7 @@
int is_ivf = 0;
if (fread(raw_hdr, 1, 32, input_ctx->file) == 32) {
- if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' &&
- raw_hdr[2] == 'I' && raw_hdr[3] == 'F') {
+ if (memcmp(IVF_SIGNATURE, raw_hdr, 4) == 0) {
is_ivf = 1;
if (mem_get_le16(raw_hdr + 4) != 0) {
@@ -105,4 +107,69 @@
}
return 1;
+}
+
+struct vpx_video {
+ FILE *file;
+ unsigned char *buffer;
+ size_t buffer_size;
+ size_t frame_size;
+ unsigned int fourcc;
+ int width;
+ int height;
+};
+
+vpx_video_t *vpx_video_open_file(FILE *file) {
+ char raw_hdr[32];
+ vpx_video_t *video;
+
+ if (fread(raw_hdr, 1, 32, file) != 32)
+ return NULL; // Can't read file header;
+
+ if (memcmp(IVF_SIGNATURE, raw_hdr, 4) != 0)
+ return NULL; // Wrong IVF signature
+
+ if (mem_get_le16(raw_hdr + 4) != 0)
+ return NULL; // Wrong IVF version
+
+ video = (vpx_video_t *)malloc(sizeof(*video));
+ video->file = file;
+ video->buffer = NULL;
+ video->buffer_size = 0;
+ video->frame_size = 0;
+ video->fourcc = mem_get_le32(raw_hdr + 8);
+ video->width = mem_get_le16(raw_hdr + 12);
+ video->height = mem_get_le16(raw_hdr + 14);
+ return video;
+}
+
+void vpx_video_close(vpx_video_t *video) {
+ if (video) {
+ free(video->buffer);
+ free(video);
+ }
+}
+
+int vpx_video_get_width(vpx_video_t *video) {
+ return video->width;
+}
+
+int vpx_video_get_height(vpx_video_t *video) {
+ return video->height;
+}
+
+unsigned int vpx_video_get_fourcc(vpx_video_t *video) {
+ return video->fourcc;
+}
+
+int vpx_video_read_frame(vpx_video_t *video) {
+ return !ivf_read_frame(video->file, &video->buffer, &video->frame_size,
+ &video->buffer_size);
+}
+
+const unsigned char *vpx_video_get_frame(vpx_video_t *video, size_t *size) {
+ if (size)
+ *size = video->frame_size;
+
+ return video->buffer;
}
--- a/ivfdec.h
+++ b/ivfdec.h
@@ -21,6 +21,34 @@
int ivf_read_frame(FILE *infile, uint8_t **buffer,
size_t *bytes_read, size_t *buffer_size);
+// The following code is work in progress. It is going to be in a separate file
+// and support transparent reading of IVF and Y4M formats. Right now only IVF
+// format is supported for simplicity. The main goal the API is to be
+// simple and easy to use in example code (and probably in vpxenc/vpxdec later).
+// All low-level details like memory buffer management are hidden from API
+// users.
+struct vpx_video;
+typedef struct vpx_video vpx_video_t;
+
+// Opens the input file and inspects it to determine file type. Returns an
+// opaque vpx_video_t* upon success, or NULL upon failure.
+vpx_video_t *vpx_video_open_file(FILE *file);
+
+// Frees all resources associated with vpx_video_t returned from
+// vpx_video_open_file() call
+void vpx_video_close(vpx_video_t *video);
+
+int vpx_video_get_width(vpx_video_t *video);
+int vpx_video_get_height(vpx_video_t *video);
+unsigned int vpx_video_get_fourcc(vpx_video_t *video);
+
+// Reads video frame bytes from the file and stores them into internal buffer.
+int vpx_video_read_frame(vpx_video_t *video);
+
+// Returns the pointer to internal memory buffer with frame bytes read from
+// last call to vpx_video_read_frame().
+const unsigned char *vpx_video_get_frame(vpx_video_t *video, size_t *size);
+
#ifdef __cplusplus
} /* extern "C" */
#endif