lavd: use libavcodec also for JPEG decompress

* mainly if GPUJPEG is not usable
This commit is contained in:
Martin Pulec
2013-01-10 16:26:08 +01:00
parent 6e7b18d470
commit d59244d9fb
5 changed files with 213 additions and 34 deletions

View File

@@ -70,6 +70,9 @@ static void restrict_returned_codecs(codec_t *display_codecs,
static void decoder_set_video_mode(struct state_decoder *decoder, unsigned int video_mode);
static int check_for_mode_change(struct state_decoder *decoder, uint32_t *hdr, struct video_frame **frame,
struct vcodec_state *pbuf_data);
static int find_best_decompress(codec_t in_codec, codec_t out_codec,
int prio_min, int prio_max, uint32_t *magic);
static bool try_initialize_decompress(struct state_decoder * decoder, uint32_t magic);
enum decoder_type_t {
UNSET,
@@ -329,6 +332,73 @@ void decoder_destroy(struct state_decoder *decoder)
free(decoder);
}
/**
* Attemps to initialize decompress of given magic
*
* @param decoder decoder state
* @param magic magic of the requested decompressor
* @return flat if initialization succeeded
*/
static bool try_initialize_decompress(struct state_decoder * decoder, uint32_t magic) {
decoder->ext_decoder = decompress_init(magic);
if(!decoder->ext_decoder) {
debug_msg("Decompressor with magic %x was not found.\n");
return false;
}
int res = 0, ret;
size_t size = sizeof(res);
ret = decompress_get_property(decoder->ext_decoder,
DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME,
&res,
&size);
if(ret && res) {
decoder->accepts_corrupted_frame = TRUE;
} else {
decoder->accepts_corrupted_frame = FALSE;
}
decoder->decoder_type = EXTERNAL_DECODER;
return true;
}
/**
* @param[in] in_codec input codec
* @param[in] out_codec output codec
* @param[in] prio_min minimal priority that can be probed
* @param[in] prio_max maximal priority that can be probed
* @param[out] magic if decompressor was found here is stored its magic
* @retval -1 if no found
* @retval priority best decoder's priority
*/
static int find_best_decompress(codec_t in_codec, codec_t out_codec,
int prio_min, int prio_max, uint32_t *magic) {
int trans;
int best_priority = prio_max + 1;
// first pass - find the one with best priority (least)
for(trans = 0; trans < decoders_for_codec_count;
++trans) {
if(in_codec == decoders_for_codec[trans].from &&
out_codec == decoders_for_codec[trans].to) {
int priority = decoders_for_codec[trans].priority;
if(priority <= prio_max &&
priority >= prio_min &&
priority < best_priority) {
if(decompress_is_available(
decoders_for_codec[trans].decompress_index)) {
best_priority = priority;
*magic = decoders_for_codec[trans].decompress_index;
}
}
}
}
if(best_priority == prio_max + 1)
return -1;
return best_priority;
}
static codec_t choose_codec_and_decoder(struct state_decoder * const decoder, struct video_desc desc,
codec_t *in_codec, decoder_t *decode_line)
{
@@ -373,14 +443,27 @@ static codec_t choose_codec_and_decoder(struct state_decoder * const decoder, st
out_codec = decoder->native_codecs[native];
if(out_codec == DVS8 || out_codec == Vuy2)
out_codec = UYVY;
if(*in_codec == line_decoders[trans].from &&
out_codec == line_decoders[trans].to) {
*decode_line = line_decoders[trans].line_decoder;
decoder->decoder_type = LINE_DECODER;
goto after_linedecoder_lookup;
int prio_max = 1000;
int prio_min = 0;
int prio_cur;
uint32_t decompress_magic = 0u;
while(1) {
prio_cur = find_best_decompress(*in_codec, out_codec,
prio_min, prio_max, &decompress_magic);
// if found, init decoder
if(prio_cur != -1) {
if(try_initialize_decompress(decoder, decompress_magic)) {
goto after_decoder_lookup;
// failed, try to find another one
prio_min = prio_cur + 1;
} else {
break;
}
}
}
}
}

View File

@@ -352,7 +352,7 @@ pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time,
curr = playout_buf->frst;
while (curr != NULL) {
if (!curr->decoded
#ifndef WIN32
#ifdef WIN32
&& tv_gt(curr_time, curr->playout_time)
#endif
) {

View File

@@ -122,15 +122,16 @@ static int decompress_fill_symbols(decoder_table_t *device)
struct decode_from_to decoders_for_codec[] = {
{ DXT1, RGBA, RTDXT_MAGIC },
{ DXT1_YUV, RGBA, RTDXT_MAGIC },
{ DXT5, RGBA, RTDXT_MAGIC },
{ DXT1, UYVY, RTDXT_MAGIC },
{ DXT1_YUV, UYVY, RTDXT_MAGIC },
{ DXT5, UYVY, RTDXT_MAGIC },
{ JPEG, RGB, JPEG_MAGIC },
{ JPEG, UYVY, JPEG_MAGIC },
{ H264, UYVY, LIBAVCODEC_MAGIC },
{ DXT1, RGBA, RTDXT_MAGIC, 500},
{ DXT1_YUV, RGBA, RTDXT_MAGIC, 500 },
{ DXT5, RGBA, RTDXT_MAGIC, 500 },
{ DXT1, UYVY, RTDXT_MAGIC, 500 },
{ DXT1_YUV, UYVY, RTDXT_MAGIC, 500 },
{ DXT5, UYVY, RTDXT_MAGIC, 500 },
{ JPEG, RGB, JPEG_MAGIC, 500 },
{ JPEG, UYVY, JPEG_MAGIC, 500 },
{ H264, UYVY, LIBAVCODEC_MAGIC, 500 },
{ JPEG, UYVY, LIBAVCODEC_MAGIC, 600 },
{ (codec_t) -1, (codec_t) -1, NULL_MAGIC }
};
const int decoders_for_codec_count = (sizeof(decoders_for_codec) / sizeof(struct decode_from_to));
@@ -186,6 +187,18 @@ void initialize_video_decompress(void)
}
}
int decompress_is_available(unsigned int decoder_index)
{
int i;
for(i = 0; i < available_decoders_count; ++i) {
if(available_decoders[i]->magic == decoder_index) {
return TRUE;
}
}
return FALSE;
}
struct state_decompress *decompress_init(unsigned int decoder_index)
{
int i;

View File

@@ -88,14 +88,36 @@ struct decode_from_to {
codec_t to;
uint32_t decompress_index;
/* priority to select this decoder if there are multiple matches
* range [0..100], lower is better
*/
int priority;
};
extern struct decode_from_to decoders_for_codec[];
extern const int decoders_for_codec_count;
/**
* must be called before initalization of decoders
*/
void initialize_video_decompress(void);
struct state_decompress *decompress_init(unsigned int decoder_index);
/**
* Checks wheather there is decompressor with given magic present and thus can
* be initialized with decompress_init
*
* @see decompress_init
* @retval TRUE if decoder is present and can be initialized
* @retval FALSE if decoder could not be initialized (not found)
*/
int decompress_is_available(unsigned int decoder_index);
/**
* Initializes decompressor or the given magic
*
* @retval NULL if initialization failed
* @retval not-NULL state of new decompressor
*/
struct state_decompress *decompress_init(unsigned int magic);
int decompress_reconfigure(struct state_decompress *, struct video_desc, int rshift, int gshift, int bshift, int pitch, codec_t out_codec);
/**
* @param frame_seq sequential number of frame

View File

@@ -55,6 +55,7 @@
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include "debug.h"
#include "video_decompress.h"
@@ -72,7 +73,8 @@ struct state_libavcodec_decompress {
int last_frame_seq;
};
static void to_yuv422(char *dst_buffer, AVFrame *in_frame);
static void yuv420p_to_yuv422(char *dst_buffer, AVFrame *in_frame);
static void yuvj422p_to_yuv422(char *dst_buffer, AVFrame *in_frame);
static void deconfigure(struct state_libavcodec_decompress *s)
{
@@ -90,37 +92,53 @@ static bool configure_with(struct state_libavcodec_decompress *s,
switch(desc.color_spec) {
case H264:
codec_id = CODEC_ID_H264;
/* find the video encoder */
break;
case JPEG:
codec_id = CODEC_ID_MJPEG;
fprintf(stderr, "[lavd] Warning: JPEG decoder "
"will use full-scale YUV.\n");
break;
default:
fprintf(stderr, "[Libavcodec] Unsupported codec!!!\n");
fprintf(stderr, "[lavd] Unsupported codec!!!\n");
return false;
}
s->codec = avcodec_find_decoder(codec_id);
if(s->codec == NULL) {
fprintf(stderr, "[Libavcodec] Unable to find codec.\n");
fprintf(stderr, "[lavd] 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");
fprintf(stderr, "[lavd] 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(s->codec->capabilities & CODEC_CAP_SLICE_THREADS) {
s->codec_ctx->thread_count = 0;
s->codec_ctx->thread_type = FF_THREAD_SLICE;
} else {
fprintf(stderr, "[lavd] Warning: Codec doesn't support slice-based multithreading.\n");
if(s->codec->capabilities & CODEC_CAP_FRAME_THREADS) {
s->codec_ctx->thread_count = 0;
s->codec_ctx->thread_type = FF_THREAD_FRAME;
} else {
fprintf(stderr, "[lavd] Warning: Codec doesn't support frame-based multithreading.\n");
}
}
s->codec_ctx->pix_fmt = PIX_FMT_YUV420P;
if(avcodec_open2(s->codec_ctx, s->codec, NULL) < 0) {
fprintf(stderr, "[Libavcodec] Unable to open decoder.\n");
fprintf(stderr, "[lavd] Unable to open decoder.\n");
return false;
}
s->frame = avcodec_alloc_frame();
if(!s->frame) {
fprintf(stderr, "[Libavcodec] Unable allocate frame.\n");
fprintf(stderr, "[lavd] Unable allocate frame.\n");
return false;
}
@@ -175,7 +193,8 @@ int libavcodec_decompress_reconfigure(void *state, struct video_desc desc,
return s->max_compressed_len;
}
static void to_yuv422(char *dst_buffer, AVFrame *in_frame)
static void yuv420p_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;
@@ -199,7 +218,28 @@ static void to_yuv422(char *dst_buffer, AVFrame *in_frame)
}
}
int libavcodec_decompress(void *state, unsigned char *dst, unsigned char *buffer,
static void yuvj422p_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; ++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 *dst = dst_buffer + in_frame->width * y * 2;
for(int x = 0; x < in_frame->width / 2; ++x) {
dst[x * 4] = src_cb[x];
dst[x * 4 + 2] = src_cr[x];
}
}
}
int libavcodec_decompress(void *state, unsigned char *dst, unsigned char *src,
unsigned int src_len, int frame_seq)
{
struct state_libavcodec_decompress *s = (struct state_libavcodec_decompress *) state;
@@ -207,12 +247,12 @@ int libavcodec_decompress(void *state, unsigned char *dst, unsigned char *buffer
int res = FALSE;
s->pkt.size = src_len;
s->pkt.data = buffer;
s->pkt.data = src;
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");
fprintf(stderr, "[lavd] Error while decoding frame.\n");
return FALSE;
}
@@ -223,11 +263,32 @@ int libavcodec_decompress(void *state, unsigned char *dst, unsigned char *buffer
(s->frame->pict_type == AV_PICTURE_TYPE_P &&
s->last_frame_seq == frame_seq - 1)
) {
to_yuv422((char *) dst, s->frame);
switch(s->frame->format) {
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
case AV_PIX_FMT_YUVJ422P:
#else
case PIX_FMT_YUVJ422P:
#endif
yuvj422p_to_yuv422((char *) dst, s->frame);
break;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
case AV_PIX_FMT_YUV420P:
#else
case PIX_FMT_YUV420P:
#endif
yuv420p_to_yuv422((char *) dst, s->frame);
break;
default:
fprintf(stderr, "Unsupported pixel "
"format: %s\n",
av_get_pix_fmt_name(
s->frame->format));
res = FALSE;
}
s->last_frame_seq = frame_seq;
res = TRUE;
} else {
fprintf(stderr, "[Libavcodec] Missing appropriate I-frame "
fprintf(stderr, "[lavd] Missing appropriate I-frame "
"(last valid %d, this %d).\n", s->last_frame_seq,
frame_seq);
res = FALSE;