32 #include <libavdevice/avdevice.h> 33 #include <libavformat/avformat.h> 34 #include <libswscale/swscale.h> 45 static unsigned int run = 1;
47 struct video_input_ctx {
48 AVFormatContext *format_ctx;
49 AVCodecContext *codec_ctx;
50 int video_stream_index;
53 static int video_input_init(
struct video_input_ctx *input_ctx,
54 const char *input_format_string,
55 const char *input_path,
56 AVDictionary **input_options)
58 AVInputFormat *input_format = NULL;
59 AVFormatContext *input_format_ctx;
60 AVCodecContext *input_codec_ctx;
66 avdevice_register_all();
67 avcodec_register_all();
70 if (input_format_string) {
72 input_format = av_find_input_format(input_format_string);
73 if (input_format == NULL) {
74 fprintf(stderr,
"cannot find input format\n");
80 if (input_path == NULL) {
81 fprintf(stderr,
"input_path must not be NULL!\n");
87 input_format_ctx = NULL;
88 ret = avformat_open_input(&input_format_ctx,
93 fprintf(stderr,
"cannot open input format/device\n");
98 ret = avformat_find_stream_info(input_format_ctx, NULL);
100 fprintf(stderr,
"cannot get information on the stream\n");
105 av_dump_format(input_format_ctx, 0, input_path, 0);
109 for (i = 0; i < input_format_ctx->nb_streams; i++)
110 if (input_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
114 if (video_index == -1) {
115 fprintf(stderr,
"cannot find any video streams\n");
121 input_codec_ctx = input_format_ctx->streams[video_index]->codec;
122 if (input_codec_ctx == NULL) {
123 fprintf(stderr,
"input codec context is not valid\n");
129 input_codec = avcodec_find_decoder(input_codec_ctx->codec_id);
130 if (input_codec == NULL) {
131 fprintf(stderr,
"input_codec is NULL!\n");
137 ret = avcodec_open2(input_codec_ctx, input_codec, NULL);
139 fprintf(stderr,
"cannot open input codec\n");
144 input_ctx->format_ctx = input_format_ctx;
145 input_ctx->codec_ctx = input_codec_ctx;
146 input_ctx->video_stream_index = video_index;
152 avformat_close_input(&input_format_ctx);
154 av_dict_free(input_options);
155 *input_options = NULL;
160 struct video_output_ctx {
161 AVCodecContext *codec_ctx;
165 static int video_output_init(
struct video_output_ctx *output_ctx,
166 struct video_input_ctx *input_ctx,
167 unsigned int upscale,
168 unsigned int quality,
172 AVCodecContext *output_codec_ctx;
173 AVCodec *output_codec;
174 unsigned int new_output_width;
175 unsigned int new_output_height;
178 if (input_ctx == NULL) {
179 fprintf(stderr,
"input_ctx must not be NULL!\n");
185 output_codec_ctx = avcodec_alloc_context3(NULL);
186 if (output_codec_ctx == NULL) {
187 fprintf(stderr,
"cannot allocate output codec context!\n");
196 (input_ctx->codec_ctx)->width,
197 (input_ctx->codec_ctx)->height,
201 fprintf(stderr,
"cannot calculate output dimension\n");
206 output_codec_ctx->bit_rate = (input_ctx->codec_ctx)->bit_rate;
207 output_codec_ctx->width = new_output_width;
208 output_codec_ctx->height = new_output_height;
209 output_codec_ctx->time_base.num =
210 (input_ctx->format_ctx)->streams[input_ctx->video_stream_index]->time_base.num;
211 output_codec_ctx->time_base.den =
212 (input_ctx->format_ctx)->streams[input_ctx->video_stream_index]->time_base.den;
218 fprintf(stdout,
"using raw output format\n");
219 output_codec_ctx->pix_fmt = AV_PIX_FMT_NV12;
220 output_ctx->codec_ctx = output_codec_ctx;
221 output_ctx->raw_output = 1;
226 output_codec_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P;
227 output_codec_ctx->codec_id = AV_CODEC_ID_MJPEG;
228 output_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
237 output_codec_ctx->qmin = output_codec_ctx->qmax = ((100 - (quality - 1)) * FF_QUALITY_SCALE) / 100;
238 output_codec_ctx->mb_lmin = output_codec_ctx->qmin * FF_QP2LAMBDA;
239 output_codec_ctx->mb_lmax = output_codec_ctx->qmax * FF_QP2LAMBDA;
240 output_codec_ctx->flags |= CODEC_FLAG_QSCALE;
241 output_codec_ctx->global_quality = output_codec_ctx->qmin * FF_QP2LAMBDA;
244 output_codec = avcodec_find_encoder(output_codec_ctx->codec_id);
245 if (output_codec == NULL) {
246 fprintf(stderr,
"cannot find output codec!\n");
252 ret = avcodec_open2(output_codec_ctx, output_codec, NULL);
254 fprintf(stderr,
"could not open output codec!\n");
258 output_ctx->codec_ctx = output_codec_ctx;
259 output_ctx->raw_output = 0;
265 avcodec_close(output_codec_ctx);
266 av_free(output_codec_ctx);
272 static int am7xxx_play(
const char *input_format_string,
273 AVDictionary **input_options,
274 const char *input_path,
275 unsigned int rescale_method,
276 unsigned int upscale,
277 unsigned int quality,
282 struct video_input_ctx input_ctx;
283 struct video_output_ctx output_ctx;
284 AVFrame *picture_raw;
285 AVFrame *picture_scaled;
288 int out_picture_size;
289 uint8_t *out_picture;
290 struct SwsContext *sw_scale_ctx;
297 ret = video_input_init(&input_ctx, input_format_string, input_path, input_options);
299 fprintf(stderr,
"cannot initialize input\n");
303 ret = video_output_init(&output_ctx, &input_ctx, upscale, quality, image_format, dev);
305 fprintf(stderr,
"cannot initialize input\n");
310 picture_raw = av_frame_alloc();
311 if (picture_raw == NULL) {
312 fprintf(stderr,
"cannot allocate the raw picture frame!\n");
318 picture_scaled = av_frame_alloc();
319 if (picture_scaled == NULL) {
320 fprintf(stderr,
"cannot allocate the scaled picture!\n");
322 goto cleanup_picture_raw;
324 picture_scaled->format = (output_ctx.codec_ctx)->pix_fmt;
325 picture_scaled->width = (output_ctx.codec_ctx)->width;
326 picture_scaled->height = (output_ctx.codec_ctx)->height;
329 out_buf_size = avpicture_get_size((output_ctx.codec_ctx)->pix_fmt,
330 (output_ctx.codec_ctx)->width,
331 (output_ctx.codec_ctx)->height);
332 out_buf = av_malloc(out_buf_size *
sizeof(uint8_t));
333 if (out_buf == NULL) {
334 fprintf(stderr,
"cannot allocate output data buffer!\n");
336 goto cleanup_picture_scaled;
340 avpicture_fill((AVPicture *)picture_scaled,
342 (output_ctx.codec_ctx)->pix_fmt,
343 (output_ctx.codec_ctx)->width,
344 (output_ctx.codec_ctx)->height);
346 sw_scale_ctx = sws_getCachedContext(NULL,
347 (input_ctx.codec_ctx)->width,
348 (input_ctx.codec_ctx)->height,
349 (input_ctx.codec_ctx)->pix_fmt,
350 (output_ctx.codec_ctx)->width,
351 (output_ctx.codec_ctx)->height,
352 (output_ctx.codec_ctx)->pix_fmt,
355 if (sw_scale_ctx == NULL) {
356 fprintf(stderr,
"cannot set up the rescaling context!\n");
358 goto cleanup_out_buf;
364 ret = av_read_frame(input_ctx.format_ctx, &in_packet);
366 if (ret == (
int)AVERROR_EOF || input_ctx.format_ctx->pb->eof_reached)
369 fprintf(stderr,
"av_read_frame failed, EOF?\n");
374 if (in_packet.stream_index != input_ctx.video_stream_index) {
382 ret = avcodec_decode_video2(input_ctx.codec_ctx, picture_raw, &got_picture, &in_packet);
384 fprintf(stderr,
"cannot decode video\n");
392 sws_scale(sw_scale_ctx,
393 (
const uint8_t *
const *)picture_raw->data,
394 picture_raw->linesize,
396 (input_ctx.codec_ctx)->height,
397 picture_scaled->data,
398 picture_scaled->linesize);
400 if (output_ctx.raw_output) {
401 out_picture = out_buf;
402 out_picture_size = out_buf_size;
404 picture_scaled->quality = (output_ctx.codec_ctx)->global_quality;
405 av_init_packet(&out_packet);
406 out_packet.data = NULL;
409 ret = avcodec_encode_video2(output_ctx.codec_ctx,
413 if (ret < 0 || !got_packet) {
414 fprintf(stderr,
"cannot encode video\n");
419 out_picture = out_packet.data;
420 out_picture_size = out_packet.size;
425 char filename[NAME_MAX];
427 if (!output_ctx.raw_output)
428 snprintf(filename, NAME_MAX,
"out_q%03d.jpg", quality);
430 snprintf(filename, NAME_MAX,
"out.raw");
431 file = fopen(filename,
"wb");
432 fwrite(out_picture, 1, out_picture_size, file);
441 (output_ctx.codec_ctx)->width,
442 (output_ctx.codec_ctx)->height,
446 perror(
"am7xxx_send_image_async");
452 if (!output_ctx.raw_output && got_packet)
453 av_free_packet(&out_packet);
454 av_free_packet(&in_packet);
457 sws_freeContext(sw_scale_ctx);
460 cleanup_picture_scaled:
461 av_frame_free(&picture_scaled);
463 av_frame_free(&picture_raw);
469 avcodec_close(output_ctx.codec_ctx);
470 av_free(output_ctx.codec_ctx);
473 avcodec_close(input_ctx.codec_ctx);
474 avformat_close_input(&(input_ctx.format_ctx));
482 static int x_get_screen_dimensions(
const char *displayname,
int *width,
int *height)
484 int i, screen_number;
485 xcb_connection_t *connection;
486 const xcb_setup_t *setup;
487 xcb_screen_iterator_t iter;
489 connection = xcb_connect(displayname, &screen_number);
490 if (xcb_connection_has_error(connection)) {
491 fprintf(stderr,
"Cannot open a connection to %s\n", displayname);
495 setup = xcb_get_setup(connection);
497 fprintf(stderr,
"Cannot get setup for %s\n", displayname);
498 xcb_disconnect(connection);
502 iter = xcb_setup_roots_iterator(setup);
503 for (i = 0; i < screen_number; ++i) {
504 xcb_screen_next(&iter);
507 xcb_screen_t *screen = iter.data;
509 *width = screen->width_in_pixels;
510 *height = screen->height_in_pixels;
512 xcb_disconnect(connection);
517 static char *get_x_screen_size(
const char *input_path)
525 ret = x_get_screen_dimensions(input_path, &width, &height);
527 fprintf(stderr,
"Cannot get screen dimensions for %s\n", input_path);
531 len = snprintf(NULL, 0,
"%dx%d", width, height);
533 screen_size = malloc((len + 1) *
sizeof(
char));
534 if (screen_size == NULL) {
539 len = snprintf(screen_size, len + 1,
"%dx%d", width, height);
548 static char *get_x_screen_size(
const char *input_path)
551 fprintf(stderr,
"%s: fallback implementation\n", __func__);
552 return strdup(
"vga");
556 static void unset_run(
int signo)
562 #ifdef HAVE_SIGACTION 563 static int set_signal_handler(
void (*signal_handler)(
int))
565 struct sigaction new_action;
566 struct sigaction old_action;
569 new_action.sa_handler = signal_handler;
570 sigemptyset(&new_action.sa_mask);
571 new_action.sa_flags = 0;
573 ret = sigaction(SIGINT, NULL, &old_action);
575 perror(
"sigaction on old_action");
579 if (old_action.sa_handler != SIG_IGN) {
580 ret = sigaction(SIGINT, &new_action, NULL);
582 perror(
"sigaction on new_action");
591 static int set_signal_handler(
void (*signal_handler)(
int))
593 (void)signal_handler;
594 fprintf(stderr,
"set_signal_handler() not implemented, sigaction not available\n");
600 static void usage(
char *name)
602 printf(
"usage: %s [OPTIONS]\n\n", name);
603 printf(
"OPTIONS:\n");
604 printf(
"\t-d <index>\t\tthe device index (default is 0)\n");
606 printf(
"\t-D \t\t\tdump the last frame to a file (only active in DEBUG mode)\n");
608 printf(
"\t-f <input format>\tthe input device format\n");
609 printf(
"\t-i <input path>\t\tthe input path\n");
610 printf(
"\t-o <options>\t\ta comma separated list of input format options\n");
611 printf(
"\t\t\t\tEXAMPLE:\n");
612 printf(
"\t\t\t\t\t-o draw_mouse=1,framerate=100,video_size=800x480\n");
613 printf(
"\t-s <scaling method>\tthe rescaling method (see swscale.h)\n");
614 printf(
"\t-u \t\t\tupscale the image if smaller than the display dimensions\n");
615 printf(
"\t-F <format>\t\tthe image format to use (default is JPEG)\n");
616 printf(
"\t\t\t\tSUPPORTED FORMATS:\n");
617 printf(
"\t\t\t\t\t1 - JPEG\n");
618 printf(
"\t\t\t\t\t2 - NV12\n");
619 printf(
"\t-q <quality>\t\tquality of jpeg sent to the device, between 1 and 100\n");
620 printf(
"\t-l <log level>\t\tthe verbosity level of libam7xxx output (0-5)\n");
621 printf(
"\t-p <power mode>\t\tthe power mode of device, between %d (off) and %d (turbo)\n",
623 printf(
"\t\t\t\tWARNING: Level 2 and greater require the master AND\n");
624 printf(
"\t\t\t\t the slave connector to be plugged in.\n");
625 printf(
"\t-z <zoom mode>\t\tthe display zoom mode, between %d (original) and %d (tele)\n",
627 printf(
"\t-h \t\t\tthis help message\n");
628 printf(
"\n\nEXAMPLES OF USE:\n");
629 printf(
"\t%s -f x11grab -i :0.0 -o video_size=800x480\n", name);
630 printf(
"\t%s -f fbdev -i /dev/fb0\n", name);
631 printf(
"\t%s -f video4linux2 -i /dev/video0 -o video_size=320x240,frame_rate=100 -u -q 90\n", name);
632 printf(
"\t%s -i http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_640x360.m4v\n", name);
635 int main(
int argc,
char *argv[])
642 char *input_format_string = NULL;
643 AVDictionary *options = NULL;
644 char *input_path = NULL;
645 unsigned int rescale_method = SWS_BICUBIC;
646 unsigned int upscale = 0;
647 unsigned int quality = 95;
649 int device_index = 0;
657 while ((opt = getopt(argc, argv,
"d:Df:i:o:s:uF:q:l:p:z:h")) != -1) {
660 device_index = atoi(optarg);
661 if (device_index < 0) {
662 fprintf(stderr,
"Unsupported device index\n");
670 fprintf(stderr,
"Warning: the -D option is only active in DEBUG mode.\n");
674 input_format_string = strdup(optarg);
677 input_path = strdup(optarg);
686 subopts = subopts_saved = strdup(optarg);
687 while ((subopt = strtok_r(subopts,
",", &subopts))) {
688 char *subopt_name = strtok_r(subopt,
"=", &subopt);
689 char *subopt_value = strtok_r(NULL,
"", &subopt);
690 if (subopt_value == NULL) {
691 fprintf(stderr,
"invalid suboption: %s\n", subopt_name);
694 av_dict_set(&options, subopt_name, subopt_value, 0);
698 fprintf(stderr,
"Option '-o' not implemented\n");
702 rescale_method = atoi(optarg);
703 switch(rescale_method) {
704 case SWS_FAST_BILINEAR:
717 fprintf(stderr,
"Unsupported rescale method\n");
726 format = atoi(optarg);
729 fprintf(stdout,
"JPEG format\n");
732 fprintf(stdout,
"NV12 format\n");
735 fprintf(stderr,
"Unsupported format\n");
741 quality = atoi(optarg);
742 if (quality < 1 || quality > 100) {
743 fprintf(stderr,
"Invalid quality value, must be between 1 and 100\n");
749 log_level = atoi(optarg);
751 fprintf(stderr,
"Unsupported log level, falling back to AM7XXX_LOG_ERROR\n");
756 power_mode = atoi(optarg);
763 fprintf(stdout,
"Power mode: %d\n", power_mode);
766 fprintf(stderr,
"Invalid power mode value, must be between %d and %d\n",
780 fprintf(stdout,
"Zoom: %d\n", zoom);
783 fprintf(stderr,
"Invalid zoom mode value, must be between %d and %d\n",
800 if (input_path == NULL) {
801 fprintf(stderr,
"The -i option must always be passed\n\n");
811 if (input_format_string && strcmp(input_format_string,
"x11grab") == 0) {
814 video_size = get_x_screen_size(input_path);
816 if (!av_dict_get(options,
"video_size", NULL, 0))
817 av_dict_set(&options,
"video_size", video_size, 0);
819 if (!av_dict_get(options,
"framerate", NULL, 0))
820 av_dict_set(&options,
"framerate",
"60", 0);
822 if (!av_dict_get(options,
"draw_mouse", NULL, 0))
823 av_dict_set(&options,
"draw_mouse",
"1", 0);
828 ret = set_signal_handler(unset_run);
836 perror(
"am7xxx_init");
844 perror(
"am7xxx_open_device");
850 perror(
"am7xxx_set_zoom_mode");
856 perror(
"am7xxx_set_power_mode");
864 ret = am7xxx_play(input_format_string,
874 fprintf(stderr,
"am7xxx_play failed\n");
881 av_dict_free(&options);
883 free(input_format_string);
Zoom test screen, the firmware version is shown as well.
Zoom 1: H Scale (changes aspect ratio).
struct _am7xxx_context am7xxx_context
An opaque data type representing a context.
Zoom Tele: available on some PicoPix models.
int am7xxx_init(am7xxx_context **ctx)
Initialize the library context and data structures, and scan for devices.
Original Size, as retrieved via am7xxx_device_info.
Max brightness and power consumption.
Middle level of brightness.
am7xxx_image_format
The image formats accepted by the device.
int am7xxx_open_device(am7xxx_context *ctx, am7xxx_device **dev, unsigned int device_index)
Open an am7xxx_device according to a index.
Zoom 2: H/V Scale (changes aspect ratio).
More brightness, but more power consumption.
Error messages, typically they describe API functions failures.
int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power)
Set the power mode of an am7xxx device.
void am7xxx_set_log_level(am7xxx_context *ctx, am7xxx_log_level log_level)
Set verbosity level of log messages.
int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, unsigned int upscale, unsigned int original_width, unsigned int original_height, unsigned int *scaled_width, unsigned int *scaled_height)
Calculate the dimensions of an image to be shown on an am7xxx device.
int am7xxx_send_image_async(am7xxx_device *dev, am7xxx_image_format format, unsigned int width, unsigned int height, unsigned char *image, unsigned int image_size)
Queue transfer of an image for display on an am7xxx device and return immediately.
Informations about the device operations.
int am7xxx_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom)
Set the zoom mode of an am7xxx device.
Raw YUV in the NV12 variant.
Verbose informations about the communication with the hardware.
Low power consumption but also low brightness.
void am7xxx_shutdown(am7xxx_context *ctx)
Cleanup the library data structures and free the context.
struct _am7xxx_device am7xxx_device
An opaque data type representing an am7xxx device.
Display is powered off, no image shown.