diff options
author | Martin Lambers <marlam@marlam.de> | 2011-05-26 10:16:58 +0400 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-05-27 18:55:07 +0400 |
commit | b8773e44d56667edea2d68d067d0c156522ca304 (patch) | |
tree | 93944768b314935a4477c27e51bca96dc2bb4716 /libavdevice/libdc1394.c | |
parent | ea7e318fb2d7a7c2395d87c93d1d5f703166ac0d (diff) |
libdc1394: choose best video mode and rate based on camera capabilities.
Diffstat (limited to 'libavdevice/libdc1394.c')
-rw-r--r-- | libavdevice/libdc1394.c | 242 |
1 files changed, 162 insertions, 80 deletions
diff --git a/libavdevice/libdc1394.c b/libavdevice/libdc1394.c index 299ae9336b..f4af08174a 100644 --- a/libavdevice/libdc1394.c +++ b/libavdevice/libdc1394.c @@ -2,6 +2,7 @@ * IIDC1394 grab interface (uses libdc1394 and libraw1394) * Copyright (c) 2004 Roman Shaposhnik * Copyright (c) 2008 Alessandro Sappia + * Copyright (c) 2011 Martin Lambers * * This file is part of FFmpeg. * @@ -25,6 +26,9 @@ #include "libavutil/opt.h" #include "avdevice.h" +#include <stdlib.h> +#include <string.h> + #include <dc1394/dc1394.h> #undef free @@ -40,16 +44,21 @@ typedef struct dc1394_data { AVPacket packet; } dc1394_data; -struct dc1394_frame_format { - int width; - int height; - enum PixelFormat pix_fmt; - int frame_size_id; -} dc1394_frame_formats[] = { - { 320, 240, PIX_FMT_UYVY422, DC1394_VIDEO_MODE_320x240_YUV422 }, - { 640, 480, PIX_FMT_UYYVYY411, DC1394_VIDEO_MODE_640x480_YUV411 }, - { 640, 480, PIX_FMT_UYVY422, DC1394_VIDEO_MODE_640x480_YUV422 }, - { 0, 0, 0, 0 } /* gotta be the last one */ +/* The list of color codings that we support. + * We assume big endian for the dc1394 16bit modes: libdc1394 never sets the + * flag little_endian in dc1394video_frame_t. */ +struct dc1394_color_coding { + int pix_fmt; + int score; + uint32_t coding; +} dc1394_color_codings[] = { + { PIX_FMT_GRAY16BE, 1000, DC1394_COLOR_CODING_MONO16 }, + { PIX_FMT_RGB48BE, 1100, DC1394_COLOR_CODING_RGB16 }, + { PIX_FMT_GRAY8, 1200, DC1394_COLOR_CODING_MONO8 }, + { PIX_FMT_RGB24, 1300, DC1394_COLOR_CODING_RGB8 }, + { PIX_FMT_UYYVYY411, 1400, DC1394_COLOR_CODING_YUV411 }, + { PIX_FMT_UYVY422, 1500, DC1394_COLOR_CODING_YUV422 }, + { PIX_FMT_NONE, 0, 0 } /* gotta be the last one */ }; struct dc1394_frame_rate { @@ -68,9 +77,6 @@ struct dc1394_frame_rate { }; static const AVOption options[] = { -#if HAVE_LIBDC1394_1 - { "channel", "", offsetof(dc1394_data, channel), FF_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, -#endif { NULL }, }; @@ -81,73 +87,22 @@ static const AVClass libdc1394_class = { .version = LIBAVUTIL_VERSION_INT, }; - -static inline int dc1394_read_common(AVFormatContext *c, AVFormatParameters *ap, - struct dc1394_frame_format **select_fmt, struct dc1394_frame_rate **select_fps) -{ - dc1394_data* dc1394 = c->priv_data; - AVStream* vst; - struct dc1394_frame_format *fmt; - struct dc1394_frame_rate *fps; - enum PixelFormat pix_fmt = ap->pix_fmt == PIX_FMT_NONE ? PIX_FMT_UYVY422 : ap->pix_fmt; /* defaults */ - int width = !ap->width ? 320 : ap->width; - int height = !ap->height ? 240 : ap->height; - int frame_rate = !ap->time_base.num ? 30000 : av_rescale(1000, ap->time_base.den, ap->time_base.num); - - for (fmt = dc1394_frame_formats; fmt->width; fmt++) - if (fmt->pix_fmt == pix_fmt && fmt->width == width && fmt->height == height) - break; - - for (fps = dc1394_frame_rates; fps->frame_rate; fps++) - if (fps->frame_rate == frame_rate) - break; - - if (!fps->frame_rate || !fmt->width) { - av_log(c, AV_LOG_ERROR, "Can't find matching camera format for %s, %dx%d@%d:1000fps\n", avcodec_get_pix_fmt_name(pix_fmt), - width, height, frame_rate); - goto out; - } - - /* create a video stream */ - vst = av_new_stream(c, 0); - if (!vst) - goto out; - av_set_pts_info(vst, 64, 1, 1000); - vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; - vst->codec->codec_id = CODEC_ID_RAWVIDEO; - vst->codec->time_base.den = fps->frame_rate; - vst->codec->time_base.num = 1000; - vst->codec->width = fmt->width; - vst->codec->height = fmt->height; - vst->codec->pix_fmt = fmt->pix_fmt; - - /* packet init */ - av_init_packet(&dc1394->packet); - dc1394->packet.size = avpicture_get_size(fmt->pix_fmt, fmt->width, fmt->height); - dc1394->packet.stream_index = vst->index; - dc1394->packet.flags |= AV_PKT_FLAG_KEY; - - dc1394->current_frame = 0; - dc1394->fps = fps->frame_rate; - - vst->codec->bit_rate = av_rescale(dc1394->packet.size * 8, fps->frame_rate, 1000); - *select_fps = fps; - *select_fmt = fmt; - return 0; -out: - return -1; -} - static int dc1394_read_header(AVFormatContext *c, AVFormatParameters * ap) { dc1394_data* dc1394 = c->priv_data; + AVStream *vst; + const struct dc1394_color_coding *cc; + const struct dc1394_frame_rate *fr; dc1394camera_list_t *list; - int res, i; - struct dc1394_frame_format *fmt = NULL; - struct dc1394_frame_rate *fps = NULL; - - if (dc1394_read_common(c,ap,&fmt,&fps) != 0) - return -1; + dc1394video_modes_t video_modes; + dc1394video_mode_t video_mode; + dc1394framerates_t frame_rates; + dc1394framerate_t frame_rate; + uint32_t dc1394_width, dc1394_height, dc1394_color_coding; + int rate, best_rate; + int score, max_score; + int final_width, final_height, final_pix_fmt, final_frame_rate; + int res, i, j; /* Now let us prep the hardware. */ dc1394->d = dc1394_new(); @@ -166,6 +121,133 @@ static int dc1394_read_header(AVFormatContext *c, AVFormatParameters * ap) /* Freeing list of cameras */ dc1394_camera_free_list (list); + /* Get the list of video modes supported by the camera. */ + res = dc1394_video_get_supported_modes (dc1394->camera, &video_modes); + if (res != DC1394_SUCCESS) { + av_log(c, AV_LOG_ERROR, "Could not get video formats.\n"); + goto out_camera; + } + /* Choose the best mode. */ + rate = (ap->time_base.num ? av_rescale(1000, ap->time_base.den, ap->time_base.num) : -1); + max_score = -1; + for (i = 0; i < video_modes.num; i++) { + if (video_modes.modes[i] == DC1394_VIDEO_MODE_EXIF + || (video_modes.modes[i] >= DC1394_VIDEO_MODE_FORMAT7_MIN + && video_modes.modes[i] <= DC1394_VIDEO_MODE_FORMAT7_MAX)) { + /* These modes are currently not supported as they would require + * much more work. For the remaining modes, the functions + * dc1394_get_image_size_from_video_mode and + * dc1394_get_color_coding_from_video_mode do not need to query the + * camera, and thus cannot fail. */ + continue; + } + dc1394_get_color_coding_from_video_mode (NULL, video_modes.modes[i], + &dc1394_color_coding); + for (cc = dc1394_color_codings; cc->pix_fmt != PIX_FMT_NONE; cc++) + if (cc->coding == dc1394_color_coding) + break; + if (cc->pix_fmt == PIX_FMT_NONE) { + /* We currently cannot handle this color coding. */ + continue; + } + /* Here we know that the mode is supported. Get its frame size and the list + * of frame rates supported by the camera for this mode. This list is sorted + * in ascending order according to libdc1394 example programs. */ + dc1394_get_image_size_from_video_mode (NULL, video_modes.modes[i], + &dc1394_width, &dc1394_height); + res = dc1394_video_get_supported_framerates (dc1394->camera, video_modes.modes[i], + &frame_rates); + if (res != DC1394_SUCCESS || frame_rates.num == 0) { + av_log(c, AV_LOG_ERROR, "Cannot get frame rates for video mode.\n"); + goto out_camera; + } + /* Choose the best frame rate. */ + best_rate = -1; + for (j = 0; j < frame_rates.num; j++) { + for (fr = dc1394_frame_rates; fr->frame_rate; fr++) { + if (fr->frame_rate_id == frame_rates.framerates[j]) { + break; + } + } + if (!fr->frame_rate) { + /* This frame rate is not supported. */ + continue; + } + best_rate = fr->frame_rate; + frame_rate = fr->frame_rate_id; + if (ap->time_base.num && rate == fr->frame_rate) { + /* This is the requested frame rate. */ + break; + } + } + if (best_rate == -1) { + /* No supported rate found. */ + continue; + } + /* Here we know that both the mode and the rate are supported. Compute score. */ + if (ap->width && ap->height + && (dc1394_width == ap->width && dc1394_height == ap->height)) { + score = 110000; + } else { + score = dc1394_width * 10; // 1600 - 16000 + } + if (ap->pix_fmt == cc->pix_fmt) { + score += 90000; + } else { + score += cc->score; // 1000 - 1500 + } + if (ap->time_base.num && rate == best_rate) { + score += 70000; + } else { + score += best_rate / 1000; // 1 - 240 + } + if (score > max_score) { + video_mode = video_modes.modes[i]; + final_width = dc1394_width; + final_height = dc1394_height; + final_pix_fmt = cc->pix_fmt; + final_frame_rate = best_rate; + max_score = score; + } + } + if (max_score == -1) { + av_log(c, AV_LOG_ERROR, "No suitable video mode / frame rate available.\n"); + goto out_camera; + } + if (ap->width && ap->height && !(ap->width == final_width && ap->height == final_height)) { + av_log(c, AV_LOG_WARNING, "Requested frame size is not available, using fallback.\n"); + } + if (ap->pix_fmt != PIX_FMT_NONE && ap->pix_fmt != final_pix_fmt) { + av_log(c, AV_LOG_WARNING, "Requested pixel format is not supported, using fallback.\n"); + } + if (ap->time_base.num && rate != final_frame_rate) { + av_log(c, AV_LOG_WARNING, "Requested frame rate is not available, using fallback.\n"); + } + + /* create a video stream */ + vst = av_new_stream(c, 0); + if (!vst) + goto out_camera; + av_set_pts_info(vst, 64, 1, 1000); + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; + vst->codec->codec_id = CODEC_ID_RAWVIDEO; + vst->codec->time_base.den = final_frame_rate; + vst->codec->time_base.num = 1000; + vst->codec->width = final_width; + vst->codec->height = final_height; + vst->codec->pix_fmt = final_pix_fmt; + + /* packet init */ + av_init_packet(&dc1394->packet); + dc1394->packet.size = avpicture_get_size(final_pix_fmt, final_width, final_height); + dc1394->packet.stream_index = vst->index; + dc1394->packet.flags |= AV_PKT_FLAG_KEY; + + dc1394->current_frame = 0; + dc1394->fps = final_frame_rate; + + vst->codec->bit_rate = av_rescale(dc1394->packet.size * 8, final_frame_rate, 1000); + /* Select MAX Speed possible from the cam */ if (dc1394->camera->bmode_capable>0) { dc1394_video_set_operation_mode(dc1394->camera, DC1394_OPERATION_MODE_1394B); @@ -182,13 +264,13 @@ static int dc1394_read_header(AVFormatContext *c, AVFormatParameters * ap) goto out_camera; } - if (dc1394_video_set_mode(dc1394->camera, fmt->frame_size_id) != DC1394_SUCCESS) { + if (dc1394_video_set_mode(dc1394->camera, video_mode) != DC1394_SUCCESS) { av_log(c, AV_LOG_ERROR, "Couldn't set video format\n"); goto out_camera; } - if (dc1394_video_set_framerate(dc1394->camera,fps->frame_rate_id) != DC1394_SUCCESS) { - av_log(c, AV_LOG_ERROR, "Couldn't set framerate %d \n",fps->frame_rate); + if (dc1394_video_set_framerate(dc1394->camera, frame_rate) != DC1394_SUCCESS) { + av_log(c, AV_LOG_ERROR, "Could not set framerate %d.\n", final_frame_rate); goto out_camera; } if (dc1394_capture_setup(dc1394->camera, 10, DC1394_CAPTURE_FLAGS_DEFAULT)!=DC1394_SUCCESS) { @@ -256,6 +338,6 @@ AVInputFormat ff_libdc1394_demuxer = { .read_header = dc1394_read_header, .read_packet = dc1394_read_packet, .read_close = dc1394_close, - .flags = AVFMT_NOFILE + .flags = AVFMT_NOFILE, .priv_class = &libdc1394_class, }; |