Commit c2b33681 authored by Dmitry Kovalev's avatar Dmitry Kovalev

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
parent 58b9c9fb
......@@ -76,9 +76,11 @@ GEN_EXAMPLES-$(CONFIG_VP8_DECODER) += postproc.c
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
......
......@@ -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 @@ static vpx_codec_iface_t *get_codec_interface(unsigned int fourcc) {
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 @@ static void print_md5(FILE *stream, unsigned char digest[16]) {
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 @@ int main(int argc, char **argv) {
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");
......@@ -167,6 +154,8 @@ int main(int argc, char **argv) {
if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec");
vpx_video_close(video);
fclose(outfile);
fclose(infile);
return EXIT_SUCCESS;
......
......@@ -8,10 +8,13 @@
* 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
......@@ -37,8 +40,7 @@ int file_is_ivf(struct VpxInputContext *input_ctx) {
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) {
......@@ -106,3 +108,68 @@ int ivf_read_frame(FILE *infile, uint8_t **buffer,
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;
}
......@@ -21,6 +21,34 @@ int file_is_ivf(struct VpxInputContext *input);
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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment