-
-
Notifications
You must be signed in to change notification settings - Fork 458
Decoder API Tutorial
This tutorial provides an introduction to writing a h265 video decoding using libde265 using the C language API.
When checking out the source repository, the source is organized into these subdirectories:
- libde265 - main library source code. Everything below libde265/encoder is required only for h265 encoding and can be omitted for a decoder-only use.
- dec265 - example h265 video decoder
- enc265 - example h265 video encoder
- sherlock265 - h265 video analysis tool (shows motion-vectors, CTB subdivisions, coding modes)
- tools - miscellaneous tools mainly for encoder development
The code inside 'libde265' is usually compiled into a link-library, while the other directories contain executable programs. We include build scripts based on autoconf and/or CMake.
libde265
is written in C++11, but provides a plain C interface for easy integration. All decoder functions are defined in the header de265.h
. This file also is the reference documentation. The header en265.h
includes the encoder API and is not needed for a decoder-only software.
This documentation refers to the new API of libde265, which is currently developed in branch frame-parallel
.
The old API for branch master
is very similar, though, and most of what is written here also applies.
First, we need to create a decoder context instance using
de265_decoder_context* de265_new_decoder(void)
The decoder uses background threads to do the actual decoding. Before using the decoder, we have to start these background threads with
de265_error de265_start_worker_threads(de265_decoder_context*, int number_of_threads)
Decoding without background threads is currently not supported. Hence, this function must be called. When the decoder is not needed any more, the decoder context must be freed again after use by
de265_error de265_free_decoder(de265_decoder_context*)
Decoding the video consists of asynchronously pushing compressed video data into the decoder context and pulling decoded frames out of the decoder. You can push in as much data as you want and pull out frames whenever you want. There exist several functions for pushing data into the decoder. The most frequently used might be
de265_error de265_push_data(de265_decoder_context*, const void* data, int length,
de265_PTS pts, void* user_data);
This pushes length
bytes of data
into the decoder. The data will be copied into the decoder context. You can also provide a pts
timestamp and user_data
. These are not actually used by the decoder, but returned again in the decoded image decoded from this data for your use. The data provided to this function should be a h265 only elementary bitstream with startcode markers.
At the end of the file, you should call
de265_error de265_flush_data(de265_decoder_context*);
to tell the decoder that no more data will follow this call. It will then flush all its output queues.
If your data consists of packetized data without startcodes, you can also push complete NAL units into the decoder context using
de265_error de265_push_NAL(de265_decoder_context*, const void* data, int length,
de265_PTS pts, void* user_data);
In order to decode the pushed data, call
de265_decode(de265_decoder_context*, int* more);
This does some decoding work, but you might have to call it several times to proceed further in the stream. It may stop either because the output picture buffer is full and you have to get these from the decoder before it will continue, or because there is not enough input data to proceed decoding.
When more
is true, the decoding is still in the middle of the stream, so you will have to call de265_decode()
again.
The returned error indicates whether you have to provide more input data (DE265_ERROR_WAITING_FOR_INPUT_DATA
) or if the
output buffer is full (DE265_ERROR_IMAGE_BUFFER_FULL
). If there is no error (DE265_OK
), simply call the function again
to proceed.
When more
is false, the end of the stream is reached, or an unrecoverable error has occurred.
Decoded images can be extracted from the decoder context using
const struct de265_image* de265_get_next_picture(de265_decoder_context*);
If there are no images available, NULL
is returned.
After use, you have to free the images with
void de265_release_picture(const de265_image*);
You can keep hold of several images, if you like, but at some time, you must release them.
This is an example for a decoding loop. For another example, see dec265/dec265.cc
.
Note that we are not checking for DE265_ERROR_IMAGE_BUFFER_FULL
since we remove all
images from the output buffer after each call to de265_decode()
.
int more = 1;
while (more) {
de265_error err = de265_decode(context, &more);
if (err == DE265_ERROR_WAITING_FOR_INPUT_DATA) {
// ... load more video data into 'buf'
de265_error err = de265_push_data(context, buf, n, 0, NULL);
...
}
const de265_image* img;
do {
// show available images
img = de265_get_next_picture(ctx);
if (img) {
// ... display image
de265_release_picture(img);
}
} while (img);
}
The de265_image*
is an opaque pointer. To access the image data, you have to use the following functions:
int de265_get_image_width(const struct de265_image*,int channel);
int de265_get_image_height(const struct de265_image*,int channel);
const uint8_t* de265_get_image_plane(const struct de265_image*, int channel, int* out_stride);
enum de265_chroma de265_get_chroma_format(const struct de265_image*);
int de265_get_bits_per_pixel(const struct de265_image*,int channel);
de265_PTS de265_get_image_PTS(const struct de265_image*);
void* de265_get_image_user_data(const struct de265_image*);
void* de265_get_image_plane_user_data(const struct de265_image*, int channel);
Channels are 0,1,2 for Y,Cb,Cr, respectively.
For high-performance decoding, you might want the decoder to decode directly into user-supplied image buffers to avoid copying of images. This is possible by writing your own stub functions for allocation and deallocation of image buffers and passing them to the decoder context.
Specifically, you have to fill in this data structure:
struct de265_image_allocation
{
int (*get_buffer)(struct de265_image_intern* img,
const struct de265_image_spec* spec,
void* alloc_userdata);
void (*release_buffer)(struct de265_image_intern* img,
void* alloc_userdata);
void* alloc_userdata;
};
The de265_image_spec
defines the properties of the image to be allocated (width, height, chroma format, alignment). The alloc_userdata
variable is passed to each call of get_buffer()
and release_buffer()
but not used otherwise by the decoder.
The get_buffer()
allocation function also received a de265_image_intern
for which the image buffers should be set. Call de265_set_image_plane_intern()
for each of the planes (Y,Cb,Cr) to set the memory buffers:
void de265_set_image_plane_intern(struct de265_image_intern* img,
int cIdx,
void* mem, int stride,
void *userdata);
The element userdata
is again optional, copied to the respective image plane of de265_image_intern
and not used by the decoder itself. You can use it, for example, when releasing the image.
Register your custom allocation function with
void de265_set_image_allocation_functions(de265_decoder_context*,
struct de265_image_allocation*);
For a complete reference to the decoder API, check the file de265.h
.