mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-04-05 06:04:50 +00:00
added libavcodec compress/decompress (H.264)
This commit is contained in:
@@ -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 $@
|
||||
|
||||
54
configure.ac
54
configure.ac
@@ -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
|
||||
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
360
src/video_compress/libavcodec.c
Normal file
360
src/video_compress/libavcodec.c
Normal 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);
|
||||
}
|
||||
|
||||
52
src/video_compress/libavcodec.h
Normal file
52
src/video_compress/libavcodec.h
Normal 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);
|
||||
@@ -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),
|
||||
|
||||
277
src/video_decompress/libavcodec.c
Normal file
277
src/video_decompress/libavcodec.c
Normal 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);
|
||||
}
|
||||
|
||||
59
src/video_decompress/libavcodec.h
Normal file
59
src/video_decompress/libavcodec.h
Normal 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);
|
||||
|
||||
Reference in New Issue
Block a user