Added support for MJPEG to libavcodec

+ parameter for specifying bitrate
This commit is contained in:
Martin Pulec
2013-01-14 11:05:27 +01:00
parent b740b65f69
commit 91ce01189c
5 changed files with 125 additions and 19 deletions

View File

@@ -65,7 +65,8 @@ typedef enum {
DPX10,
JPEG,
RAW,
H264
H264,
MJPG
} codec_t;
enum interlacing_t {

View File

@@ -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}
};

View File

@@ -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 */

View File

@@ -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));

View File

@@ -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 "