mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-04-05 17:04:53 +00:00
lavd: use libavcodec also for JPEG decompress
* mainly if GPUJPEG is not usable
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user