Evaluating x264 -- first steps encoding greylevel images
Eeri Kask <Eeri.Kask <at> inf.tu-dresden.de>
2010-03-12 13:20:06 GMT
Hello,
being new to x264 and just a moment ago subscribed to this list let
me describe some issues I got stuck with while starting learning
x264 (and h264 in general).
I have a task to encode some intermediate numerical simulation image
data for efficient storage and later review. ("Efficient" storage in
the sense of replacing thousands of PNG frame files by a single,
preferrably lossless, or at least a "high-quality" video file.)
Having completed the simulation, in order to avoid manually recoding
these PNG files into a H264 file it would be purposeful to put some
x264-interface glue code to into that above simulation program in
order to create the H264 file on the fly.
So I investigated x264 a little and undertook some experimentation;
in particular, taking the x264.c source file as a learning sample I
tried to spot and extract the essential core parts in order to
achieve the following. Given a file of stored raw 8-bit greylevel
data (the raw-file size is the number-of-frames times frame width
times frame height in bytes), then read this file from stdin and
output h264 stream into stdout. The frame rate and frame size are
expected on the command line. Let me attach the 90-line C source of
this tiny first application here as "Grey8_to_H264.c" which should
do exactly that.
Having compiled, the simplest use case for that small tool is
probably this:
dd if=/dev/random count=100 bs=15000 \
| grey8_to_h264 10 150 100 > random.h264
The first part creates 100 frames sized 150x100 of greylevel
random-noise, and the resulting h264 stream is stored in random.h264
as a 10 fps raw-video.
The problem with the above tool is, it either crashes x264, or sends
it into a possibly never-ending loop; depending if the only '#if 1'
in the above source is '1' or '0'. I am using the latest git-source
of x264.
May I kindly ask anybody knowledgeable to give a quick look at this
source code to point out if there is some obvious problem with it;
and how it should be changed in order to complete the posed task...
Huge thanks in advance for any comments and suggestions,
Eeri Kask
P.S. Compiling the above source against some considerably older x264
of 2009, it completes as expected but if then creating mp4 container
around random.h264 by
MP4Box -add random.h264 -fps 10 -keep-sys -flat random.h264.mp4
then a mp4-stream with an interesting frame-size (probably due to
crf = 0 above) is created:
AVC-H264 import - frame size 90 x -52 at 10.000 FPS
Import results: 85 samples - Slices: 30 I 71 P 0 B - 2 SEI - 4 IDR
Saving random.h264.mp4: Flat storage
but this is probably a completely different issue, unrelated to x264.
/*
gcc -O1 -o ${HBIN:-.}/grey8_to_h264 Grey8_to_H264.c -lx264
dd if=/dev/random count=100 bs=15000 | grey8_to_h264 10 150 100 > random.h264
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <x264.h>
static int EncodeFrame (FILE *out, x264_t *h, x264_picture_t *pic)
{
x264_picture_t pic_out;
x264_nal_t *p_nal;
int i_nal, i_frame_size;
i_frame_size = x264_encoder_encode (h, &p_nal, &i_nal, pic, &pic_out);
if (i_frame_size < 0)
fprintf (stderr, "EncodeFrame(): x264_encoder_encode() failed.\n");
if (i_frame_size > 0)
i_frame_size = fwrite (p_nal[0].p_payload, i_frame_size, 1, out);
return i_frame_size;
}
static int Grey8_to_H264 (FILE *in, FILE *out, int fps, int width, int height)
{
int c = 1;
x264_t *h;
x264_picture_t pic;
x264_param_t param;
x264_param_default (¶m);
#if 1
x264_param_parse (¶m, "threads", "1"); /* <-- avoid endless loop*/
x264_param_parse (¶m, "crf", "0"); /* <-- enforce lossless encoding*/
#endif
param.i_width = width;
param.i_height = height;
param.i_fps_num = fps;
param.i_fps_den = 1;
h = x264_encoder_open (¶m);
if (h != (x264_t*)(0)) {
if (x264_picture_alloc (&pic, param.i_csp, param.i_width, param.i_height) == 0) {
x264_nal_t *p_nal;
int i_nal;
if (x264_encoder_headers (h, &p_nal, &i_nal) >= 0) {
if (fwrite (p_nal[0].p_payload, (p_nal[0].i_payload + p_nal[1].i_payload + p_nal[2].i_payload),
1, out) > 0)
{
int cnt = 0;
memset (pic.img.plane[1], /*u*/ 128, (param.i_width/2)*(param.i_height/2)); /*have no color*/
memset (pic.img.plane[2], /*v*/ 128, (param.i_width/2)*(param.i_height/2)); /*have no color*/
/*encode sequence*/
while (feof(in) == 0)
{
for (c = 0; c < param.i_width*param.i_height && feof(in) == 0; ++c) /*read frame, i.e. 'y'*/
((unsigned char*)(pic.img.plane[0]))[c] = (unsigned char)(fgetc(in));
pic.i_pts = cnt++; /* <-- what is this?*/
pic.i_type = X264_TYPE_AUTO; /* <-- what is this?*/
pic.i_qpplus1 = 0; /* <-- what is this?*/
if (EncodeFrame (out, h, &pic) < 0)
break;
}
/*flush*/
while (x264_encoder_delayed_frames (h) > 0)
if (EncodeFrame (out, h, &pic) < 0)
break;
c = 0;
}
}
x264_picture_clean (&pic);
}
x264_encoder_close (h);
}
return c;
}
int main (int argc, char *argv[])
{
int fps, width, height;
if (argc >= 4
&& sscanf (argv[1], " %d", &fps) == 1 && fps > 0
&& sscanf (argv[2], " %d", &width) == 1 && width > 0
&& sscanf (argv[3], " %d", &height) == 1 && height > 0)
return Grey8_to_H264 (stdin, stdout, fps, width, height);
fprintf (stderr, "Usage: %s framerate framewidth frameheight < grey8stream.data > stream.h264\n", argv[0]);
return 1;
}
_______________________________________________
x264-devel mailing list
x264-devel <at> videolan.org
http://mailman.videolan.org/listinfo/x264-devel