Commit 10d104e4 authored by Philip Gladstone's avatar Philip Gladstone

* Add frame rate conversion when there is no audio channel. This makes

  ffmpeg/ffserver work again when just capturing video from a live
  source and you are streaming feeds of different frame rates.
* Fix a segfault in argument processing
* Add handling for -vhook argument
* Add logic to call video hooks if any have been specified.

Originally committed as revision 1247 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 142fc6b9
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
*/ */
#define HAVE_AV_CONFIG_H #define HAVE_AV_CONFIG_H
#include "avformat.h" #include "avformat.h"
#include "framehook.h"
#ifndef CONFIG_WIN32 #ifndef CONFIG_WIN32
#include <unistd.h> #include <unistd.h>
...@@ -447,6 +448,46 @@ static void write_picture(AVFormatContext *s, int index, AVPicture *picture, ...@@ -447,6 +448,46 @@ static void write_picture(AVFormatContext *s, int index, AVPicture *picture,
av_free(buf); av_free(buf);
} }
static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
UINT8 *buf = 0;
dec = &ist->st->codec;
/* deinterlace : must be done before any resize */
if (do_deinterlace) {
int size;
/* create temporary picture */
size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
buf = av_malloc(size);
if (!buf)
return;
picture2 = &picture_tmp;
avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
if (avpicture_deinterlace(picture2, picture,
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not deinterlace */
av_free(buf);
buf = NULL;
picture2 = picture;
}
} else {
picture2 = picture;
}
frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height);
if (picture != picture2)
*picture = *picture2;
*bufp = buf;
}
/* we begin to correct av delay at this threshold */ /* we begin to correct av delay at this threshold */
#define AV_DELAY_MAX 0.100 #define AV_DELAY_MAX 0.100
...@@ -457,8 +498,8 @@ static void do_video_out(AVFormatContext *s, ...@@ -457,8 +498,8 @@ static void do_video_out(AVFormatContext *s,
int *frame_size, AVOutputStream *audio_sync) int *frame_size, AVOutputStream *audio_sync)
{ {
int nb_frames, i, ret; int nb_frames, i, ret;
AVPicture *picture, *picture2, *pict; AVPicture *picture, *pict;
AVPicture picture_tmp1, picture_tmp2; AVPicture picture_tmp1;
static UINT8 *video_buffer; static UINT8 *video_buffer;
UINT8 *buf = NULL, *buf1 = NULL; UINT8 *buf = NULL, *buf1 = NULL;
AVCodecContext *enc, *dec; AVCodecContext *enc, *dec;
...@@ -496,8 +537,18 @@ static void do_video_out(AVFormatContext *s, ...@@ -496,8 +537,18 @@ static void do_video_out(AVFormatContext *s,
else if (av_delay > AV_DELAY_MAX) else if (av_delay > AV_DELAY_MAX)
nb_frames = 0; nb_frames = 0;
} }
} else {
double vdelta;
if (ost->sync_ipts != AV_NOPTS_VALUE) {
vdelta = (double)(ost->st->pts.val) * s->pts_num / s->pts_den - ost->sync_ipts;
if (vdelta < -AV_DELAY_MAX)
nb_frames = 2;
else if (vdelta > AV_DELAY_MAX)
nb_frames = 0;
//printf("vdelta=%f\n", vdelta);
}
} }
/* XXX: also handle frame rate conversion */
if (nb_frames <= 0) if (nb_frames <= 0)
return; return;
...@@ -506,30 +557,6 @@ static void do_video_out(AVFormatContext *s, ...@@ -506,30 +557,6 @@ static void do_video_out(AVFormatContext *s,
if (!video_buffer) if (!video_buffer)
return; return;
/* deinterlace : must be done before any resize */
if (do_deinterlace) {
int size;
/* create temporary picture */
size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
buf1 = av_malloc(size);
if (!buf1)
return;
picture2 = &picture_tmp2;
avpicture_fill(picture2, buf1, dec->pix_fmt, dec->width, dec->height);
if (avpicture_deinterlace(picture2, picture1,
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not deinterlace */
av_free(buf1);
buf1 = NULL;
picture2 = picture1;
}
} else {
picture2 = picture1;
}
/* convert pixel format if needed */ /* convert pixel format if needed */
if (enc->pix_fmt != dec->pix_fmt) { if (enc->pix_fmt != dec->pix_fmt) {
int size; int size;
...@@ -543,13 +570,13 @@ static void do_video_out(AVFormatContext *s, ...@@ -543,13 +570,13 @@ static void do_video_out(AVFormatContext *s,
avpicture_fill(pict, buf, enc->pix_fmt, dec->width, dec->height); avpicture_fill(pict, buf, enc->pix_fmt, dec->width, dec->height);
if (img_convert(pict, enc->pix_fmt, if (img_convert(pict, enc->pix_fmt,
picture2, dec->pix_fmt, picture1, dec->pix_fmt,
dec->width, dec->height) < 0) { dec->width, dec->height) < 0) {
fprintf(stderr, "pixel format conversion not handled\n"); fprintf(stderr, "pixel format conversion not handled\n");
goto the_end; goto the_end;
} }
} else { } else {
pict = picture2; pict = picture1;
} }
/* XXX: resampling could be done before raw format convertion in /* XXX: resampling could be done before raw format convertion in
...@@ -690,6 +717,10 @@ void print_report(AVFormatContext **output_files, ...@@ -690,6 +717,10 @@ void print_report(AVFormatContext **output_files,
ost = ost_table[i]; ost = ost_table[i];
os = output_files[ost->file_index]; os = output_files[ost->file_index];
enc = &ost->st->codec; enc = &ost->st->codec;
if (vid && enc->codec_type == CODEC_TYPE_VIDEO) {
sprintf(buf + strlen(buf), "q=%2d ",
enc->quality);
}
if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) { if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) {
frame_number = ost->frame_number; frame_number = ost->frame_number;
sprintf(buf + strlen(buf), "frame=%5d q=%2d ", sprintf(buf + strlen(buf), "frame=%5d q=%2d ",
...@@ -1019,8 +1050,8 @@ static int av_encode(AVFormatContext **output_files, ...@@ -1019,8 +1050,8 @@ static int av_encode(AVFormatContext **output_files,
AVCodec *codec; AVCodec *codec;
codec = avcodec_find_decoder(ist->st->codec.codec_id); codec = avcodec_find_decoder(ist->st->codec.codec_id);
if (!codec) { if (!codec) {
fprintf(stderr, "Unsupported codec for input stream #%d.%d\n", fprintf(stderr, "Unsupported codec (id=%d) for input stream #%d.%d\n",
ist->file_index, ist->index); ist->st->codec.codec_id, ist->file_index, ist->index);
exit(1); exit(1);
} }
if (avcodec_open(&ist->st->codec, codec) < 0) { if (avcodec_open(&ist->st->codec, codec) < 0) {
...@@ -1075,6 +1106,7 @@ static int av_encode(AVFormatContext **output_files, ...@@ -1075,6 +1106,7 @@ static int av_encode(AVFormatContext **output_files,
int data_size, got_picture; int data_size, got_picture;
AVPicture picture; AVPicture picture;
short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2];
void *buffer_to_free;
double pts_min; double pts_min;
redo: redo:
...@@ -1221,6 +1253,11 @@ static int av_encode(AVFormatContext **output_files, ...@@ -1221,6 +1253,11 @@ static int av_encode(AVFormatContext **output_files,
ptr += ret; ptr += ret;
len -= ret; len -= ret;
buffer_to_free = 0;
if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) {
pre_process_video_frame(ist, &picture, &buffer_to_free);
}
ist->frame_decoded = 1; ist->frame_decoded = 1;
#if 0 #if 0
...@@ -1257,6 +1294,9 @@ static int av_encode(AVFormatContext **output_files, ...@@ -1257,6 +1294,9 @@ static int av_encode(AVFormatContext **output_files,
/* XXX: take into account the various fifos, /* XXX: take into account the various fifos,
in particular for audio */ in particular for audio */
ost->sync_opts = ost->st->pts.val; ost->sync_opts = ost->st->pts.val;
//printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt.pts=%lld\n", ipts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt.pts);
} else {
//printf("pts.val=%lld\n", ost->st->pts.val);
} }
if (ost->encoding_needed) { if (ost->encoding_needed) {
...@@ -1296,6 +1336,7 @@ static int av_encode(AVFormatContext **output_files, ...@@ -1296,6 +1336,7 @@ static int av_encode(AVFormatContext **output_files,
} }
} }
} }
av_free(buffer_to_free);
ipts = AV_NOPTS_VALUE; ipts = AV_NOPTS_VALUE;
} }
discard_packet: discard_packet:
...@@ -1719,6 +1760,25 @@ void opt_audio_codec(const char *arg) ...@@ -1719,6 +1760,25 @@ void opt_audio_codec(const char *arg)
} }
} }
void add_frame_hooker(const char *arg)
{
int argc = 0;
char *argv[64];
int i;
char *args = strdup(arg);
argv[0] = strtok(args, " ");
while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) {
}
i = frame_hook_add(argc, argv);
if (i != 0) {
fprintf(stderr, "Failed to add video hook function: %s\n", arg);
exit(1);
}
}
const char *motion_str[] = { const char *motion_str[] = {
"zero", "zero",
"full", "full",
...@@ -2489,6 +2549,7 @@ const OptionDef options[] = { ...@@ -2489,6 +2549,7 @@ const OptionDef options[] = {
{ "psnr", OPT_BOOL | OPT_EXPERT, {(void*)&do_psnr}, "calculate PSNR of compressed frames" }, { "psnr", OPT_BOOL | OPT_EXPERT, {(void*)&do_psnr}, "calculate PSNR of compressed frames" },
{ "vstats", OPT_BOOL | OPT_EXPERT, {(void*)&do_vstats}, "dump video coding statistics to file" }, { "vstats", OPT_BOOL | OPT_EXPERT, {(void*)&do_vstats}, "dump video coding statistics to file" },
{ "bitexact", OPT_EXPERT, {(void*)opt_bitexact}, "only use bit exact algorithms (for codec testing)" }, { "bitexact", OPT_EXPERT, {(void*)opt_bitexact}, "only use bit exact algorithms (for codec testing)" },
{ "vhook", HAS_ARG | OPT_EXPERT, {(void*)add_frame_hooker}, "insert video processing module", "module name and parameters" },
{ NULL, }, { NULL, },
}; };
...@@ -2526,8 +2587,13 @@ int main(int argc, char **argv) ...@@ -2526,8 +2587,13 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
arg = NULL; arg = NULL;
if (po->flags & HAS_ARG) if (po->flags & HAS_ARG) {
arg = argv[optindex++]; arg = argv[optindex++];
if (!arg) {
fprintf(stderr, "%s: missing argument for option '%s'\n", argv[0], opt);
exit(1);
}
}
if (po->flags & OPT_STRING) { if (po->flags & OPT_STRING) {
char *str; char *str;
str = strdup(arg); str = strdup(arg);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment