mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-22 07:40:24 +00:00
Added support for MJPEG to libavcodec
+ parameter for specifying bitrate
This commit is contained in:
@@ -65,7 +65,8 @@ typedef enum {
|
||||
DPX10,
|
||||
JPEG,
|
||||
RAW,
|
||||
H264
|
||||
H264,
|
||||
MJPG
|
||||
} codec_t;
|
||||
|
||||
enum interlacing_t {
|
||||
|
||||
@@ -79,7 +79,8 @@ const struct codec_info_t codec_info[] = {
|
||||
{DPX10, "DPX10", to_fourcc('D','P','1','0'), 1, 4.0, TRUE, FALSE},
|
||||
{JPEG, "JPEG", to_fourcc('J','P','E','G'), 0, 0.0, FALSE, TRUE},
|
||||
{RAW, "raw", to_fourcc('r','a','w','s'), 0, 1.0, FALSE, TRUE}, /* raw SDI */
|
||||
{H264, "H264", to_fourcc('A','V','V','1'), 0, 1.0, FALSE, TRUE},
|
||||
{H264, "H.264", to_fourcc('A','V','C','1'), 0, 1.0, FALSE, TRUE},
|
||||
{MJPG, "MJPEG", to_fourcc('M','J','P','G'), 0, 1.0, FALSE, TRUE},
|
||||
{(codec_t) 0, NULL, 0, 0, 0.0, FALSE, FALSE}
|
||||
};
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
#include "video.h"
|
||||
#include "video_codec.h"
|
||||
|
||||
#define DEFAULT_CODEC CODEC_ID_H264
|
||||
#define DEFAULT_CODEC H264
|
||||
|
||||
struct libav_video_compress {
|
||||
struct video_frame *out[2];
|
||||
@@ -79,15 +79,29 @@ struct libav_video_compress {
|
||||
unsigned char *decoded;
|
||||
decoder_t decoder;
|
||||
|
||||
codec_t selected_codec_id;
|
||||
int requested_bitrate;
|
||||
|
||||
bool configured;
|
||||
};
|
||||
|
||||
static void to_yuv420(AVFrame *out_frame, unsigned char *in_data);
|
||||
static void usage(void);
|
||||
|
||||
static void usage() {
|
||||
printf("Libavcodec encoder usage:\n");
|
||||
printf("\t-c libavcodec[:codec=<codec_name>][:bitrate=<bits_per_sec>]"
|
||||
"[qscale=<qcoef>\n");
|
||||
printf("\t\t<codec_name> may be one of \"MJPEG\" "
|
||||
"or \"H.264\" (default)\n");
|
||||
printf("\t\t<bits_per_sec> specifies requested bitrate\n");
|
||||
printf("\t\t\t0 means codec default (same as when parameter omitted)\n");
|
||||
}
|
||||
|
||||
void * libavcodec_compress_init(char * fmt)
|
||||
{
|
||||
UNUSED(fmt);
|
||||
struct libav_video_compress *s;
|
||||
char *item, *save_ptr = NULL;
|
||||
|
||||
s = (struct libav_video_compress *) malloc(sizeof(struct libav_video_compress));
|
||||
s->out[0] = s->out[1] = NULL;
|
||||
@@ -96,6 +110,57 @@ void * libavcodec_compress_init(char * fmt)
|
||||
s->codec = NULL;
|
||||
s->codec_ctx = NULL;
|
||||
s->in_frame = NULL;
|
||||
s->selected_codec_id = DEFAULT_CODEC;
|
||||
|
||||
s->requested_bitrate = -1;
|
||||
|
||||
if(fmt) {
|
||||
while((item = strtok_r(fmt, ":", &save_ptr)) != NULL) {
|
||||
if(strncasecmp("help", item, strlen("help")) == 0) {
|
||||
usage();
|
||||
return NULL;
|
||||
} else if(strncasecmp("codec=", item, strlen("codec=")) == 0) {
|
||||
char *codec = item + strlen("codec=");
|
||||
int i;
|
||||
for (i = 0; codec_info[i].name != NULL; i++) {
|
||||
if (strcmp(codec, codec_info[i].name) == 0) {
|
||||
s->selected_codec_id = codec_info[i].codec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(codec_info[i].name == NULL) {
|
||||
fprintf(stderr, "[lavd] Unable to find codec: \"%s\"\n", codec);
|
||||
return NULL;
|
||||
}
|
||||
} else if(strncasecmp("bitrate=", item, strlen("bitrate=")) == 0) {
|
||||
char *bitrate_str = item + strlen("bitrate=");
|
||||
char *end_ptr;
|
||||
char unit_prefix_u;
|
||||
s->requested_bitrate = strtoul(bitrate_str, &end_ptr, 10);
|
||||
unit_prefix_u = toupper(*end_ptr);
|
||||
switch(unit_prefix_u) {
|
||||
case 'G':
|
||||
s->requested_bitrate *= 1000;
|
||||
case 'M':
|
||||
s->requested_bitrate *= 1000;
|
||||
case 'K':
|
||||
s->requested_bitrate *= 1000;
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "[lavc] Error: unknown unit prefix %c.\n",
|
||||
*end_ptr);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "[lavc] Error: unknown option %s.\n",
|
||||
item);
|
||||
return NULL;
|
||||
}
|
||||
fmt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
s->decoded = NULL;
|
||||
|
||||
@@ -117,21 +182,42 @@ void * libavcodec_compress_init(char * fmt)
|
||||
static bool configure_with(struct libav_video_compress *s, struct video_frame *frame)
|
||||
{
|
||||
int ret;
|
||||
int codec_id = DEFAULT_CODEC;
|
||||
int codec_id;
|
||||
int pix_fmt;
|
||||
double avg_bpp; // average bite per pixel
|
||||
// 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:
|
||||
switch(s->selected_codec_id) {
|
||||
case H264:
|
||||
codec_id = CODEC_ID_H264;
|
||||
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
|
||||
pix_fmt = AV_PIX_FMT_YUV420P;
|
||||
#else
|
||||
pix_fmt = PIX_FMT_YUV420P;
|
||||
#endif
|
||||
compressed_desc.color_spec = H264;
|
||||
// from H.264 Primer
|
||||
avg_bpp =
|
||||
4 * /* for H.264: 1 - low motion, 2 - medium motion, 4 - high motion */
|
||||
0.07;
|
||||
break;
|
||||
case MJPG:
|
||||
codec_id = CODEC_ID_MJPEG;
|
||||
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
|
||||
pix_fmt = AV_PIX_FMT_YUVJ420P;
|
||||
#else
|
||||
pix_fmt = PIX_FMT_YUVJ420P;
|
||||
#endif
|
||||
compressed_desc.color_spec = MJPG;
|
||||
avg_bpp = 0.7;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "[Libavcodec] Unable to match "
|
||||
"desired codec to UltraGrid internal "
|
||||
"one.\n");
|
||||
fprintf(stderr, "[lavc] Requested output codec isn't "
|
||||
"supported by libavcodec.\n");
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -147,7 +233,7 @@ static bool configure_with(struct libav_video_compress *s, struct video_frame *f
|
||||
/* 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"
|
||||
fprintf(stderr, "Libavcodec doesn't contain specified codec.\n"
|
||||
"Hint: Check if you have libavcodec-extra package installed.\n");
|
||||
return false;
|
||||
}
|
||||
@@ -160,9 +246,14 @@ static bool configure_with(struct libav_video_compress *s, struct video_frame *f
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(s->requested_bitrate > 0) {
|
||||
s->codec_ctx->bit_rate = s->requested_bitrate;
|
||||
} else {
|
||||
s->codec_ctx->bit_rate = frame->tiles[0].width * frame->tiles[0].height *
|
||||
avg_bpp * frame->fps;
|
||||
}
|
||||
s->codec_ctx->bit_rate_tolerance = s->codec_ctx->bit_rate / 4;
|
||||
|
||||
/* resolution must be a multiple of two */
|
||||
s->codec_ctx->width = frame->tiles[0].width;
|
||||
s->codec_ctx->height = frame->tiles[0].height;
|
||||
@@ -187,11 +278,8 @@ static bool configure_with(struct libav_video_compress *s, struct video_frame *f
|
||||
"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->codec_ctx->pix_fmt = pix_fmt;
|
||||
|
||||
s->decoded = malloc(frame->tiles[0].width * frame->tiles[0].height * 4);
|
||||
|
||||
@@ -199,6 +287,20 @@ static bool configure_with(struct libav_video_compress *s, struct video_frame *f
|
||||
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);
|
||||
} else {
|
||||
// zero should mean count equal to the number of virtual cores
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* open it */
|
||||
|
||||
@@ -132,6 +132,7 @@ struct decode_from_to decoders_for_codec[] = {
|
||||
{ JPEG, UYVY, JPEG_MAGIC, 500 },
|
||||
{ H264, UYVY, LIBAVCODEC_MAGIC, 500 },
|
||||
{ JPEG, UYVY, LIBAVCODEC_MAGIC, 600 },
|
||||
{ MJPG, UYVY, LIBAVCODEC_MAGIC, 500 },
|
||||
{ (codec_t) -1, (codec_t) -1, NULL_MAGIC }
|
||||
};
|
||||
const int decoders_for_codec_count = (sizeof(decoders_for_codec) / sizeof(struct decode_from_to));
|
||||
|
||||
@@ -96,6 +96,7 @@ static bool configure_with(struct state_libavcodec_decompress *s,
|
||||
case H264:
|
||||
codec_id = CODEC_ID_H264;
|
||||
break;
|
||||
case MJPG:
|
||||
case JPEG:
|
||||
codec_id = CODEC_ID_MJPEG;
|
||||
fprintf(stderr, "[lavd] Warning: JPEG decoder "
|
||||
|
||||
Reference in New Issue
Block a user