added libavcodec compress/decompress (H.264)

This commit is contained in:
Martin Pulec
2013-01-10 12:37:56 +01:00
parent 96c3c9094a
commit 673c49ead4
8 changed files with 826 additions and 0 deletions

View File

@@ -447,6 +447,7 @@ alsa: @ALSA_PLAY_LIB_TARGET@ @ALSA_CAP_LIB_TARGET@
portaudio: @PORTAUDIO_PLAY_LIB_TARGET@ @PORTAUDIO_CAP_LIB_TARGET@
jack: @JACK_CAP_LIB_TARGET@ @JACK_PLAY_LIB_TARGET@
scale: @SCALE_LIB_TARGET@
libavcodec: @LIBAVCODEC_DECOMPRESS_LIB_TARGET@ @LIBAVCODEC_COMPRESS_LIB_TARGET@
@SDL_LIB_TARGET@: @SDL_OBJ@
mkdir -p lib/ultragrid
@@ -512,6 +513,14 @@ scale: @SCALE_LIB_TARGET@
mkdir -p lib/ultragrid
$(LINKER) $(LDFLAGS) -shared -Wl,-soname,vcompress_uyvy.so.@video_compress_abi_version@ @GL_COMMON_OBJ@ @UYVY_COMPRESS_OBJ@ -o $@
@LIBAVCODEC_COMPRESS_LIB_TARGET@: @LIBAVCODEC_COMPRESS_OBJ@
mkdir -p lib/ultragrid
$(LINKER) $(LDFLAGS) -shared -Wl,-soname,vcompress_libavcodec.so.@video_compress_abi_version@ $^ @LIBAVCODEC_LIBS@ -o $@
@LIBAVCODEC_DECOMPRESS_LIB_TARGET@: @LIBAVCODEC_DECOMPRESS_OBJ@
mkdir -p lib/ultragrid
$(LINKER) $(LDFLAGS) -shared -Wl,-soname,vdecompress_libavcodec.so.@video_decompress_abi_version@ $^ @LIBAVCODEC_LIBS@ -o $@
@JPEG_COMPRESS_LIB_TARGET@: @JPEG_COMPRESS_OBJ@ @JPEG_COMMON_OBJ@
mkdir -p lib/ultragrid
$(LINKER) $(LDFLAGS) -shared -Wl,-soname,vcompress_jpeg.so.@video_compress_abi_version@ $^ @JPEG_LIB@ -o $@

View File

@@ -2027,8 +2027,60 @@ AC_SUBST(V4L2_OBJ)
LIB_MODULES="$LIB_MODULES $V4L2_LIBS"
# -------------------------------------------------------------------------------------------------
# Libav
# -------------------------------------------------------------------------------------------------
libavcodec=no
AC_ARG_ENABLE(libavcodec,
AS_HELP_STRING([--disable-libavcodec], [disable libavcodec support(default is auto)]),
[libavcodec_req=$enableval],
[libavcodec_req=yes]
)
#PKG_CHECK_MODULES([LIBAVCODEC], [libavcodec], [found_libavcodec=yes], [found_libavcodec=no])
AC_CHECK_HEADERS([libavcodec/avcodec.h libavutil/imgutils.h libavutil/opt.h])
AC_CHECK_LIB(avcodec, avcodec_open2)
if test $ac_cv_header_libavcodec_avcodec_h = yes -a \
$ac_cv_header_libavutil_imgutils_h = yes -a \
$ac_cv_header_libavutil_opt_h = yes -a \
$ac_cv_lib_avcodec_avcodec_open2 = yes
then
found_libavcodec=yes
LIBAVCODEC_LIBS="-lavcodec"
else
found_libavcodec=no
fi
if test $libavcodec_req = yes -a $found_libavcodec = yes
then
LIBAVCODEC_OBJ="src/video_compress/libavcodec.o"
AC_DEFINE([HAVE_LIBAVCODEC], [1], [Build with LIBAVCODEC support])
AC_SUBST(LIBAVCODEC_COMPRESS_LIB_TARGET, "lib/ultragrid/vcompress_libavcodec.so.$video_compress_abi_version")
AC_SUBST(LIBAVCODEC_DECOMPRESS_LIB_TARGET, "lib/ultragrid/vdecompress_libavcodec.so.$video_decompress_abi_version")
LIB_TARGETS="$LIB_TARGETS $LIBAVCODEC_COMPRESS_LIB_TARGET $LIBAVCODEC_DECOMPRESS_LIB_TARGET"
LIBAVCODEC_COMPRESS_OBJ=src/video_compress/libavcodec.o
LIBAVCODEC_DECOMPRESS_OBJ=src/video_decompress/libavcodec.o
LIB_OBJS="$LIB_OBJS $LIBAVCODEC_COMPRESS_OBJ $LIBAVCODEC_DECOMPRESS_OBJ"
CFLAGS="$CFLAGS $LIBAVCODEC_CFLAGS"
libavcodec=yes
SAVED_LIBS=$LIBS
LIBS="$LIBS $LIBAVCODEC_LIBS"
AC_CHECK_FUNCS(avcodec_encode_video2)
LIBS=$SAVED_LIBS
else
LIBAVCODEC_LIBS=
LIBAVCODEC_OBJ=
fi
AC_SUBST(LIBAVCODEC_LIBS) # set by pkg-config
AC_SUBST(LIBAVCODEC_COMPRESS_OBJ)
AC_SUBST(LIBAVCODEC_DECOMPRESS_OBJ)
LIB_MODULES="$LIB_MODULES $LIBAVCODEC_LIBS"
# -------------------------------------------------------------------------------------------------
# We need to add libraries then
# -------------------------------------------------------------------------------------------------
# this is only needed when passing to "clean" make target
if test "$build_libraries" = yes
@@ -2062,6 +2114,7 @@ Configuring JPEG
/bin/sh -c "cd gpujpeg; ./configure --with-cuda=$CUDA_PATH"
fi
LIB_MODULES="$LIB_MODULES $V4L2_LIBS"
# -------------------------------------------------------------------------------------------------
# Finally, substitute things into the Makefile and config.h
@@ -2095,6 +2148,7 @@ RESULT=\
Realtime DXT (OpenGL) ....... $rtdxt
JPEG ........................ $jpeg (static: $jpeg_static)
UYVY dummy compression ...... $uyvy
Libavcodec .................. $libavcodec
scale postprocessor ......... $scale
testcard extras ............. $testcard_extras_req

View File

@@ -57,6 +57,7 @@
#include "video_compress.h"
#include "video_compress/dxt_glsl.h"
#include "video_compress/fastdxt.h"
#include "video_compress/libavcodec.h"
#include "video_compress/jpeg.h"
#include "video_compress/none.h"
#include "video_compress/uyvy.h"
@@ -99,6 +100,9 @@ struct compress_t compress_modules[] = {
#endif
#if defined HAVE_COMPRESS_UYVY || defined BUILD_LIBRARIES
{"UYVY", "uyvy", MK_NAME(uyvy_compress_init), MK_NAME(uyvy_compress), MK_NAME(uyvy_compress_done), NULL},
#endif
#if defined HAVE_LIBAVCODEC || defined BUILD_LIBRARIES
{"libavcodec", "libavcodec", MK_NAME(libavcodec_compress_init), MK_NAME(libavcodec_compress), MK_NAME(libavcodec_compress_done), NULL},
#endif
{"none", NULL, MK_STATIC(none_compress_init), MK_STATIC(none_compress), MK_STATIC(none_compress_done), NULL},
};

View File

@@ -0,0 +1,360 @@
/*
* FILE: video_compress/libavcodec.c
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2011 CESNET z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif // HAVE_CONFIG_H
#include "video_compress/libavcodec.h"
#include <assert.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include "debug.h"
#include "host.h"
#include "video.h"
#include "video_codec.h"
#define DEFAULT_CODEC CODEC_ID_H264
struct libav_video_compress {
struct video_frame *out[2];
struct video_desc saved_desc;
AVFrame *in_frame;
AVCodec *codec;
AVCodecContext *codec_ctx;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
AVPacket pkt[2];
#endif
unsigned char *decoded;
decoder_t decoder;
bool configured;
};
static void to_yuv420(AVFrame *out_frame, unsigned char *in_data);
void * libavcodec_compress_init(char * fmt)
{
UNUSED(fmt);
struct libav_video_compress *s;
s = (struct libav_video_compress *) malloc(sizeof(struct libav_video_compress));
s->out[0] = s->out[1] = NULL;
s->configured = false;
s->codec = NULL;
s->codec_ctx = NULL;
s->in_frame = NULL;
s->decoded = NULL;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
for(int i = 0; i < 2; ++i) {
av_init_packet(&s->pkt[i]);
s->pkt[i].data = NULL;
s->pkt[i].size = 0;
}
#endif
/* register all the codecs (you can also register only the codec
* you wish to have smaller code */
avcodec_register_all();
return s;
}
static bool configure_with(struct libav_video_compress *s, struct video_frame *frame)
{
int ret;
int codec_id = DEFAULT_CODEC;
// implement multiple tiles support if needed
assert(frame->tile_count == 1);
s->saved_desc = video_desc_from_frame(frame);
struct video_desc compressed_desc;
compressed_desc = video_desc_from_frame(frame);
switch(codec_id) {
case CODEC_ID_H264:
compressed_desc.color_spec = H264;
break;
default:
fprintf(stderr, "[Libavcodec] Unable to match "
"desired codec to UltraGrid internal "
"one.\n");
return false;
}
for(int i = 0; i < 2; ++i) {
s->out[i] = vf_alloc_desc(compressed_desc);
#ifndef HAVE_AVCODEC_ENCODE_VIDEO2
s->out[i]->tiles[0].data = malloc(compressed_desc.width *
compressed_desc.height * 4);
#endif // HAVE_AVCODEC_ENCODE_VIDEO2
}
/* find the video encoder */
s->codec = avcodec_find_encoder(codec_id);
if (!s->codec) {
fprintf(stderr, "Libavcodec doesn't contain specified codec (H.264).\n"
"Hint: Check if you have libavcodec-extra package installed.\n");
return false;
}
// avcodec_alloc_context3 allocates context and sets default value
s->codec_ctx = avcodec_alloc_context3(s->codec);
if (!s->codec_ctx) {
fprintf(stderr, "Could not allocate video codec context\n");
return false;
}
/* put parameters */
s->codec_ctx->bit_rate = frame->tiles[0].width * frame->tiles[0].height *
4 * /* for H.264: 1 - low motion, 2 - medium motion, 4 - high motion */
0.07 * frame->fps;
/* resolution must be a multiple of two */
s->codec_ctx->width = frame->tiles[0].width;
s->codec_ctx->height = frame->tiles[0].height;
/* frames per second */
s->codec_ctx->time_base= (AVRational){1,(int) frame->fps};
s->codec_ctx->gop_size = 20; /* emit one intra frame every ten frames */
s->codec_ctx->max_b_frames = 0;
switch(frame->color_spec) {
case Vuy2:
case DVS8:
case UYVY:
s->decoder = (decoder_t) memcpy;
break;
case YUYV:
s->decoder = (decoder_t) vc_copylineYUYV;
break;
case v210:
s->decoder = (decoder_t) vc_copylinev210;
break;
default:
fprintf(stderr, "[Libavcodec] Unable to find "
"appropriate pixel format.\n");
return false;
}
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
s->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
#else
s->codec_ctx->pix_fmt = PIX_FMT_YUV420P;
#endif
s->decoded = malloc(frame->tiles[0].width * frame->tiles[0].height * 4);
if(codec_id == CODEC_ID_H264) {
av_opt_set(s->codec_ctx->priv_data, "preset", "ultrafast", 0);
//av_opt_set(s->codec_ctx->priv_data, "tune", "fastdecode", 0);
av_opt_set(s->codec_ctx->priv_data, "tune", "zerolatency", 0);
}
/* open it */
if (avcodec_open2(s->codec_ctx, s->codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
return false;
}
s->in_frame = avcodec_alloc_frame();
if (!s->in_frame) {
fprintf(stderr, "Could not allocate video frame\n");
return false;
}
s->in_frame->format = s->codec_ctx->pix_fmt;
s->in_frame->width = s->codec_ctx->width;
s->in_frame->height = s->codec_ctx->height;
/* the image can be allocated by any means and av_image_alloc() is
* just the most convenient way if av_malloc() is to be used */
ret = av_image_alloc(s->in_frame->data, s->in_frame->linesize,
s->codec_ctx->width, s->codec_ctx->height,
s->codec_ctx->pix_fmt, 32);
if (ret < 0) {
fprintf(stderr, "Could not allocate raw picture buffer\n");
return false;
}
return true;
}
static void to_yuv420(AVFrame *out_frame, unsigned char *in_data)
{
for(int y = 0; y < (int) out_frame->height; ++y) {
unsigned char *src = in_data + out_frame->width * y * 2;
unsigned char *dst_y = out_frame->data[0] + out_frame->linesize[0] * y;
for(int x = 0; x < out_frame->width; ++x) {
dst_y[x] = src[x * 2 + 1];
}
}
for(int y = 0; y < (int) out_frame->height / 2; ++y) {
/* every even row */
unsigned char *src1 = in_data + (y * 2) * (out_frame->width * 2);
/* every odd row */
unsigned char *src2 = in_data + (y * 2 + 1) * (out_frame->width * 2);
unsigned char *dst_cb = out_frame->data[1] + out_frame->linesize[1] * y;
unsigned char *dst_cr = out_frame->data[2] + out_frame->linesize[2] * y;
for(int x = 0; x < out_frame->width / 2; ++x) {
dst_cb[x] = (src1[x * 4] + src2[x * 4]) / 2;
dst_cr[x] = (src1[x * 4 + 2] + src1[x * 4 + 2]) / 2;
}
}
}
struct video_frame * libavcodec_compress(void *arg, struct video_frame * tx, int buffer_idx)
{
struct libav_video_compress *s = (struct libav_video_compress *) arg;
assert (buffer_idx == 0 || buffer_idx == 1);
static int frame_seq = 0;
int ret;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
int got_output;
#endif
if(!s->configured) {
int ret = configure_with(s, tx);
if(!ret) {
return NULL;
}
s->configured = true;
} else {
// reconfiguration not yet implemented
assert(video_desc_eq(video_desc_from_frame(tx),
s->saved_desc));
}
s->in_frame->pts = frame_seq++;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
av_free_packet(&s->pkt[buffer_idx]);
av_init_packet(&s->pkt[buffer_idx]);
s->pkt[buffer_idx].data = NULL;
s->pkt[buffer_idx].size = 0;
#endif
unsigned char *line1 = (unsigned char *) tx->tiles[0].data;
unsigned char *line2 = (unsigned char *) s->decoded;
int src_linesize = vc_get_linesize(tx->tiles[0].width, tx->color_spec);
int dst_linesize = tx->tiles[0].width * 2; /* UYVY */
for (int i = 0; i < (int) tx->tiles[0].height; ++i) {
s->decoder(line2, line1, dst_linesize,
0, 8, 16);
line1 += src_linesize;
line2 += dst_linesize;
}
to_yuv420(s->in_frame, s->decoded);
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
/* encode the image */
ret = avcodec_encode_video2(s->codec_ctx, &s->pkt[buffer_idx],
s->in_frame, &got_output);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
return NULL;
}
if (got_output) {
//printf("Write frame %3d (size=%5d)\n", frame_seq, s->pkt[buffer_idx].size);
s->out[buffer_idx]->tiles[0].data = (char *) s->pkt[buffer_idx].data;
s->out[buffer_idx]->tiles[0].data_len = s->pkt[buffer_idx].size;
} else {
return NULL;
}
#else
/* encode the image */
ret = avcodec_encode_video(s->codec_ctx, (uint8_t *) s->out[buffer_idx]->tiles[0].data,
s->out[buffer_idx]->tiles[0].width * s->out[buffer_idx]->tiles[0].height * 4,
s->in_frame);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
return NULL;
}
if (ret) {
//printf("Write frame %3d (size=%5d)\n", frame_seq, s->pkt[buffer_idx].size);
s->out[buffer_idx]->tiles[0].data_len = ret;
} else {
return NULL;
}
#endif // HAVE_AVCODEC_ENCODE_VIDEO2
return s->out[buffer_idx];
}
void libavcodec_compress_done(void *arg)
{
struct libav_video_compress *s = (struct libav_video_compress *) arg;
for(int i = 0; i < 2; ++i) {
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
vf_free(s->out[i]);
av_free_packet(&s->pkt[i]);
#else
vf_free_data(s->out[i]);
#endif // HAVE_AVCODEC_ENCODE_VIDEO2
}
if(s->codec_ctx)
avcodec_close(s->codec_ctx);
if(s->in_frame) {
av_freep(s->in_frame->data);
av_free(s->in_frame);
}
av_free(s->codec_ctx);
free(s->decoded);
free(s);
}

View File

@@ -0,0 +1,52 @@
/*
* FILE: video_compress.h
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2010 CESNET z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
struct video_frame;
void *libavcodec_compress_init(char * opts);
struct video_frame *libavcodec_compress(void *args, struct video_frame * tx, int buffer);
void libavcodec_compress_done(void *args);

View File

@@ -57,6 +57,7 @@
#include "video_decompress.h"
#include "video_decompress/dxt_glsl.h"
#include "video_decompress/jpeg.h"
#include "video_decompress/libavcodec.h"
#include "video_decompress/null.h"
#include "lib_common.h"
@@ -129,6 +130,7 @@ struct decode_from_to decoders_for_codec[] = {
{ DXT5, UYVY, RTDXT_MAGIC },
{ JPEG, RGB, JPEG_MAGIC },
{ JPEG, UYVY, JPEG_MAGIC },
{ H264, UYVY, LIBAVCODEC_MAGIC },
{ (codec_t) -1, (codec_t) -1, NULL_MAGIC }
};
const int decoders_for_codec_count = (sizeof(decoders_for_codec) / sizeof(struct decode_from_to));
@@ -143,6 +145,15 @@ decoder_table_t decoders[] = {
{ JPEG_MAGIC, "jpeg", MK_NAME(jpeg_decompress_init), MK_NAME(jpeg_decompress_reconfigure),
MK_NAME(jpeg_decompress), MK_NAME(jpeg_decompress_get_property),
MK_NAME(jpeg_decompress_done), NULL},
#endif
#if defined HAVE_LIBAVCODEC || defined BUILD_LIBRARIES
{ LIBAVCODEC_MAGIC, "libavcodec",
MK_NAME(libavcodec_decompress_init),
MK_NAME(libavcodec_decompress_reconfigure),
MK_NAME(libavcodec_decompress),
MK_NAME(libavcodec_decompress_get_property),
MK_NAME(libavcodec_decompress_done),
NULL},
#endif
{ NULL_MAGIC, NULL, MK_STATIC(null_decompress_init), MK_STATIC(null_decompress_reconfigure),
MK_STATIC(null_decompress), MK_NAME(null_decompress_get_property),

View File

@@ -0,0 +1,277 @@
/*
* FILE: video_decompress/dxt_glsl.c
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2011 CESNET z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif // HAVE_CONFIG_H
#include "video_decompress/libavcodec.h"
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include "debug.h"
#include "video_decompress.h"
struct state_libavcodec_decompress {
AVCodec *codec;
AVCodecContext *codec_ctx;
AVFrame *frame;
AVPacket pkt;
int pitch;
int rshift, gshift, bshift;
int max_compressed_len;
int last_frame_seq;
};
static void to_yuv422(char *dst_buffer, AVFrame *in_frame);
static void deconfigure(struct state_libavcodec_decompress *s)
{
if(s->codec_ctx)
avcodec_close(s->codec_ctx);
av_free(s->codec_ctx);
av_free(s->frame);
av_free_packet(&s->pkt);
}
static bool configure_with(struct state_libavcodec_decompress *s,
struct video_desc desc)
{
int codec_id;
switch(desc.color_spec) {
case H264:
codec_id = CODEC_ID_H264;
/* find the video encoder */
break;
default:
fprintf(stderr, "[Libavcodec] Unsupported codec!!!\n");
return false;
}
s->codec = avcodec_find_decoder(codec_id);
if(s->codec == NULL) {
fprintf(stderr, "[Libavcodec] Unable to find codec.\n");
return false;
}
s->codec_ctx = avcodec_alloc_context3(s->codec);
if(s->codec_ctx == NULL) {
fprintf(stderr, "[Libavcodec] Unable to allocate codec context.\n");
return false;
}
// zero should mean count equal to the number of virtual cores
s->codec_ctx->thread_count = 0;
s->codec_ctx->thread_type = FF_THREAD_SLICE;
if(avcodec_open2(s->codec_ctx, s->codec, NULL) < 0) {
fprintf(stderr, "[Libavcodec] Unable to open decoder.\n");
return false;
}
s->frame = avcodec_alloc_frame();
if(!s->frame) {
fprintf(stderr, "[Libavcodec] Unable allocate frame.\n");
return false;
}
av_init_packet(&s->pkt);
s->last_frame_seq = -1;
return true;
}
void * libavcodec_decompress_init(void)
{
struct state_libavcodec_decompress *s;
s = (struct state_libavcodec_decompress *)
malloc(sizeof(struct state_libavcodec_decompress));
/* register all the codecs (you can also register only the codec
* you wish to have smaller code */
avcodec_register_all();
s->codec_ctx = NULL;;
s->frame = NULL;
av_init_packet(&s->pkt);
s->pkt.data = NULL;
s->pkt.size = 0;
return s;
}
int libavcodec_decompress_reconfigure(void *state, struct video_desc desc,
int rshift, int gshift, int bshift, int pitch, codec_t out_codec)
{
struct state_libavcodec_decompress *s =
(struct state_libavcodec_decompress *) state;
// assume that we have the same pitch as line size, for now
assert(pitch == vc_get_linesize(desc.width, out_codec));
// TODO: add also RGB output codecs if possible
assert(out_codec == UYVY);
s->pitch = pitch;
s->rshift = rshift;
s->gshift = gshift;
s->bshift = bshift;
deconfigure(s);
configure_with(s, desc);
s->max_compressed_len = 4 * desc.width * desc.height;
return s->max_compressed_len;
}
static void to_yuv422(char *dst_buffer, AVFrame *in_frame)
{
for(int y = 0; y < (int) in_frame->height; ++y) {
char *src = (char *) in_frame->data[0] + in_frame->linesize[0] * y;
char *dst = (char *) dst_buffer + in_frame->width * y * 2;
for(int x = 0; x < in_frame->width; ++x) {
dst[x * 2 + 1] = src[x];
}
}
for(int y = 0; y < (int) in_frame->height / 2; ++y) {
char *src_cb = (char *) in_frame->data[1] + in_frame->linesize[1] * y;
char *src_cr = (char *) in_frame->data[2] + in_frame->linesize[2] * y;
char *dst1 = dst_buffer + in_frame->width * (y * 2) * 2;
char *dst2 = dst_buffer + (y * 2 + 1) * in_frame->width * 2;
for(int x = 0; x < in_frame->width / 2; ++x) {
dst1[x * 4] = src_cb[x];
dst1[x * 4 + 2] = src_cr[x];
dst2[x * 4] = src_cb[x];
dst2[x * 4 + 2] = src_cr[x];
}
}
}
int libavcodec_decompress(void *state, unsigned char *dst, unsigned char *buffer,
unsigned int src_len, int frame_seq)
{
struct state_libavcodec_decompress *s = (struct state_libavcodec_decompress *) state;
int len, got_frame;
int res = FALSE;
s->pkt.size = src_len;
s->pkt.data = buffer;
while (s->pkt.size > 0) {
len = avcodec_decode_video2(s->codec_ctx, s->frame, &got_frame, &s->pkt);
if(len < 0) {
fprintf(stderr, "[Libavcodec] Error while decoding frame.\n");
return FALSE;
}
if(got_frame) {
/* pass frame only if this is I-frame or we have complete
* GOP (assuming we are not using B-frames */
if(s->frame->pict_type == AV_PICTURE_TYPE_I ||
(s->frame->pict_type == AV_PICTURE_TYPE_P &&
s->last_frame_seq == frame_seq - 1)
) {
to_yuv422((char *) dst, s->frame);
s->last_frame_seq = frame_seq;
res = TRUE;
} else {
fprintf(stderr, "[Libavcodec] Missing appropriate I-frame "
"(last valid %d, this %d).\n", s->last_frame_seq,
frame_seq);
res = FALSE;
}
}
if(s->pkt.data) {
s->pkt.size -= len;
s->pkt.data += len;
}
}
return res;
}
int libavcodec_decompress_get_property(void *state, int property, void *val, size_t *len)
{
struct state_libavcodec_decompress *s =
(struct state_libavcodec_decompress *) state;
UNUSED(s);
int ret = FALSE;
switch(property) {
case DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME:
if(*len >= sizeof(int)) {
*(int *) val = FALSE;
*len = sizeof(int);
ret = TRUE;
}
break;
default:
ret = FALSE;
}
return ret;
}
void libavcodec_decompress_done(void *state)
{
struct state_libavcodec_decompress *s =
(struct state_libavcodec_decompress *) state;
deconfigure(s);
free(s);
}

View File

@@ -0,0 +1,59 @@
/*
* FILE: video_decompress/dxt_glsl.c
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2010 CESNET z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "video_codec.h"
#define LIBAVCODEC_MAGIC 0xff2f1b41u
void *libavcodec_decompress_init(void);
int libavcodec_decompress_reconfigure(void *state, struct video_desc desc,
int rshift, int gshift, int bshift, int pitch, codec_t out_codec);
int libavcodec_decompress(void *state, unsigned char *dst,
unsigned char *buffer, unsigned int src_len, int frame_seq);
int libavcodec_decompress_get_property(void *state, int property, void *val, size_t *len);
void libavcodec_decompress_done(void *state);