Merge tag 'v0.1.6' into debian
authorAntonio Ospite <ao2@ao2.it>
Tue, 17 Nov 2015 15:39:40 +0000 (16:39 +0100)
committerAntonio Ospite <ao2@ao2.it>
Tue, 17 Nov 2015 15:39:40 +0000 (16:39 +0100)
Release version 0.1.6

13 files changed:
NEWS
TODO
contrib/am7xxx-play-window.sh
contrib/performance/0001-Instrument-code-with-fps-meter.patch
doc/Doxyfile.in
doc/lsusb_dumps/lsusb_Philips-PicoPix-1020.log [new file with mode: 0644]
examples/CMakeLists.txt
examples/am7xxx-modeswitch.c
examples/am7xxx-play.c
examples/picoproj.c
src/am7xxx.c
src/am7xxx.h
src/portable_endian.h

diff --git a/NEWS b/NEWS
index e23a882..4b63b2d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,25 @@
+News for v0.1.6:
+================
+
+  * Fix some ffmpeg compile time deprecation warnings in am7xxx-play
+  * Fix some fmmpeg runtime warnings
+  * Don't dump the last frame unconditionally in am7xxx-play when in DEBUG
+    mode, add an option to enable the frame dump, but this is only active in
+    DEBUG mode
+  * Fix some compilation warnings from clang
+  * Replace deprecated FFmpeg API symbol PIX_FMT_NV12 in am7xx-play (Thanks to
+    Andreas Cadhalpun)
+  * Fix the Length field in the switch command in am7xxx-modeswitch (Thanks to
+    Balasubramanian S)
+  * More robust handling of USB configurations
+  * More robust handling of kernel driver detachment (Thanks to Andrea
+    Console)
+  * Minor documentation cleanups
+  * Minor build system improvements (am7xxx-play can now build without XCB,
+    but some functionalities will not be available)
+  * Misc code cleanups
+  * Relicense the example under GPL-3+
+
 News for v0.1.5:
 ================
 
diff --git a/TODO b/TODO
index 1ce3068..46bf8de 100644 (file)
--- a/TODO
+++ b/TODO
@@ -4,3 +4,8 @@
   (this may not be necessary if the GStreamer sink works well enough).
 - If there will ever be an API breakage, consider using more portable types
   (e.g.  off_t for file sizes, size_t for counters, etc.)
+- uniform the style of if() checks in cmake files
+- evaluate the use of error() instead of debug() for error paths
+- make the switch_command in am7xxx-modeswitch more readable using the
+  explicit bulk_cb_wrap structure from include/linux/usb/storage.h in the
+  linux kernel.
index 2978ef2..dd8703d 100755 (executable)
 set -e
 
 DISPLAY=":0"
+
 WIN_INFO="$(xwininfo)"
+
 X=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Absolute upper-left X:[[:space:]]*/s///p")
 Y=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Absolute upper-left Y:[[:space:]]*/s///p")
 WIDTH=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Width:[[:space:]]*/s///p")
 HEIGHT=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Height:[[:space:]]*/s///p")
+
 set -x
 am7xxx-play -f x11grab -i "${DISPLAY}+${X},${Y}" -o video_size="${WIDTH}x${HEIGHT}"
index 5c133ee..ef81acb 100644 (file)
@@ -1,6 +1,6 @@
-From dc6b216ffea1e80fd3f43d6144eb679a193f5666 Mon Sep 17 00:00:00 2001
-From: Antonio Ospite <ospite@studenti.unina.it>
-Date: Sun, 28 Jul 2013 01:06:41 +0200
+From ab3f910957638300224f1f114df6e73115ec86b7 Mon Sep 17 00:00:00 2001
+From: Antonio Ospite <ao2@ao2.it>
+Date: Tue, 17 Nov 2015 16:28:03 +0100
 Subject: [PATCH] Instrument code with fps-meter
 X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM<pyWR#k60!#=#>/Vb;]yA5<GWI5`6u&+
  ;6b'@y|8w"wB;4/e!7wYYrcqdJFY,~%Gk_4]cq$Ei/7<j&N3ah(m`ku?pX.&+~:_/wC~dwn^)MizBG
@@ -10,22 +10,22 @@ Instrument code with fps-meter:
 http://git.ao2.it/experiments/fps-meter.git/
 ---
  examples/CMakeLists.txt | 2 +-
- examples/am7xxx-play.c  | ++++
- 2 files changed, 5 insertions(+), 1 deletion(-)
+ examples/am7xxx-play.c  | 5 +++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
 
 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
-index c77a812..23af8a9 100644
+index c563f5f..4bdbdec 100644
 --- a/examples/CMakeLists.txt
 +++ b/examples/CMakeLists.txt
 @@ -1,5 +1,5 @@
  include(CheckSymbolExists)
 -add_definitions("-D_POSIX_C_SOURCE=2") # for getopt()
-+add_definitions("-D_POSIX_C_SOURCE=200112L") # for getopt()
++add_definitions("-D_POSIX_C_SOURCE=200112L") # for clock_gettime()
  add_definitions("-D_POSIX_SOURCE") # for sigaction
  add_definitions("-D_BSD_SOURCE") # for strdup
  
 diff --git a/examples/am7xxx-play.c b/examples/am7xxx-play.c
-index 3230e67..17228bf 100644
+index 6b0d206..271677b 100644
 --- a/examples/am7xxx-play.c
 +++ b/examples/am7xxx-play.c
 @@ -34,6 +34,7 @@
@@ -36,7 +36,7 @@ index 3230e67..17228bf 100644
  
  /* On some systems ENOTSUP is not defined, fallback to its value on
   * linux which is equal to EOPNOTSUPP which is 95
-@@ -292,6 +293,7 @@ static int am7xxx_play(const char *input_format_string,
+@@ -293,6 +294,7 @@ static int am7xxx_play(const char *input_format_string,
        int got_picture;
        int got_packet;
        int ret;
@@ -44,15 +44,16 @@ index 3230e67..17228bf 100644
  
        ret = video_input_init(&input_ctx, input_format_string, input_path, input_options);
        if (ret < 0) {
-@@ -354,6 +356,7 @@ static int am7xxx_play(const char *input_format_string,
+@@ -358,6 +360,8 @@ static int am7xxx_play(const char *input_format_string,
                goto cleanup_out_buf;
        }
  
 +      fps_meter_init(&stats);
++
+       got_packet = 0;
        while (run) {
                /* read packet */
-               ret = av_read_frame(input_ctx.format_ctx, &in_packet);
-@@ -438,6 +441,7 @@ static int am7xxx_play(const char *input_format_string,
+@@ -447,6 +451,7 @@ static int am7xxx_play(const char *input_format_string,
                                run = 0;
                                goto end_while;
                        }
@@ -61,5 +62,5 @@ index 3230e67..17228bf 100644
  end_while:
                if (!output_ctx.raw_output && got_packet)
 -- 
-1.8.3.2
+2.6.2
 
index e44ed39..fa85ae9 100644 (file)
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.4
+# Doxyfile 1.8.8
 
 #---------------------------------------------------------------------------
 # Project related configuration options
@@ -10,6 +10,7 @@ PROJECT_BRIEF          = "@PROJECT_DESCRIPTION@"
 PROJECT_LOGO           =
 OUTPUT_DIRECTORY       = @DOC_OUTPUT_PATH@
 CREATE_SUBDIRS         = NO
+ALLOW_UNICODE_NAMES    = NO
 OUTPUT_LANGUAGE        = English
 BRIEF_MEMBER_DESC      = YES
 REPEAT_BRIEF           = YES
@@ -63,6 +64,7 @@ INTERNAL_DOCS          = NO
 CASE_SENSE_NAMES       = YES
 HIDE_SCOPE_NAMES       = NO
 SHOW_INCLUDE_FILES     = YES
+SHOW_GROUPED_MEMB_INC  = NO
 FORCE_LOCAL_INCLUDES   = NO
 INLINE_INFO            = YES
 SORT_MEMBER_DOCS       = YES
@@ -84,7 +86,7 @@ FILE_VERSION_FILTER    =
 LAYOUT_FILE            =
 CITE_BIB_FILES         =
 #---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 QUIET                  = NO
 WARNINGS               = YES
@@ -94,7 +96,7 @@ WARN_NO_PARAMDOC       = NO
 WARN_FORMAT            = "$file:$line: $text"
 WARN_LOGFILE           =
 #---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
 #---------------------------------------------------------------------------
 INPUT                  = @CMAKE_CURRENT_SOURCE_DIR@/ \
                          @CMAKE_SOURCE_DIR@/src/ \
@@ -118,7 +120,7 @@ FILTER_SOURCE_FILES    = NO
 FILTER_SOURCE_PATTERNS =
 USE_MDFILE_AS_MAINPAGE =
 #---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
 #---------------------------------------------------------------------------
 SOURCE_BROWSER         = YES
 INLINE_SOURCES         = YES
@@ -126,16 +128,19 @@ STRIP_CODE_COMMENTS    = YES
 REFERENCED_BY_RELATION = NO
 REFERENCES_RELATION    = NO
 REFERENCES_LINK_SOURCE = YES
+SOURCE_TOOLTIPS        = YES
 USE_HTAGS              = NO
 VERBATIM_HEADERS       = YES
+CLANG_ASSISTED_PARSING = NO
+CLANG_OPTIONS          =
 #---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
 #---------------------------------------------------------------------------
 ALPHABETICAL_INDEX     = YES
 COLS_IN_ALPHA_INDEX    = 5
 IGNORE_PREFIX          =
 #---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
 #---------------------------------------------------------------------------
 GENERATE_HTML          = YES
 HTML_OUTPUT            = html
@@ -193,7 +198,7 @@ SEARCHDATA_FILE        = searchdata.xml
 EXTERNAL_SEARCH_ID     =
 EXTRA_SEARCH_MAPPINGS  =
 #---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
+# Configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 GENERATE_LATEX         = NO
 LATEX_OUTPUT           = latex
@@ -212,7 +217,7 @@ LATEX_HIDE_INDICES     = NO
 LATEX_SOURCE_CODE      = NO
 LATEX_BIB_STYLE        = plain
 #---------------------------------------------------------------------------
-# configuration options related to the RTF output
+# Configuration options related to the RTF output
 #---------------------------------------------------------------------------
 GENERATE_RTF           = NO
 RTF_OUTPUT             = rtf
@@ -221,31 +226,31 @@ RTF_HYPERLINKS         = NO
 RTF_STYLESHEET_FILE    =
 RTF_EXTENSIONS_FILE    =
 #---------------------------------------------------------------------------
-# configuration options related to the man page output
+# Configuration options related to the man page output
 #---------------------------------------------------------------------------
 GENERATE_MAN           = NO
 MAN_OUTPUT             = man
 MAN_EXTENSION          = .3
+MAN_SUBDIR             =
 MAN_LINKS              = NO
 #---------------------------------------------------------------------------
-# configuration options related to the XML output
+# Configuration options related to the XML output
 #---------------------------------------------------------------------------
 GENERATE_XML           = NO
 XML_OUTPUT             = xml
-XML_SCHEMA             =
-XML_DTD                =
 XML_PROGRAMLISTING     = YES
 #---------------------------------------------------------------------------
-# configuration options related to the DOCBOOK output
+# Configuration options related to the DOCBOOK output
 #---------------------------------------------------------------------------
 GENERATE_DOCBOOK       = NO
 DOCBOOK_OUTPUT         = docbook
+DOCBOOK_PROGRAMLISTING = NO
 #---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 GENERATE_AUTOGEN_DEF   = NO
 #---------------------------------------------------------------------------
-# configuration options related to the Perl module output
+# Configuration options related to the Perl module output
 #---------------------------------------------------------------------------
 GENERATE_PERLMOD       = NO
 PERLMOD_LATEX          = NO
@@ -264,7 +269,7 @@ PREDEFINED             =
 EXPAND_AS_DEFINED      =
 SKIP_FUNCTION_MACROS   = YES
 #---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration options related to external references
 #---------------------------------------------------------------------------
 TAGFILES               =
 GENERATE_TAGFILE       =
@@ -277,6 +282,7 @@ PERL_PATH              = /usr/bin/perl
 #---------------------------------------------------------------------------
 CLASS_DIAGRAMS         = NO
 MSCGEN_PATH            =
+DIA_PATH               =
 HIDE_UNDOC_RELATIONS   = YES
 HAVE_DOT               = NO
 DOT_NUM_THREADS        = 0
@@ -300,6 +306,8 @@ INTERACTIVE_SVG        = NO
 DOT_PATH               =
 DOTFILE_DIRS           =
 MSCFILE_DIRS           =
+DIAFILE_DIRS           =
+PLANTUML_JAR_PATH      =
 DOT_GRAPH_MAX_NODES    = 50
 MAX_DOT_GRAPH_DEPTH    = 0
 DOT_TRANSPARENT        = NO
diff --git a/doc/lsusb_dumps/lsusb_Philips-PicoPix-1020.log b/doc/lsusb_dumps/lsusb_Philips-PicoPix-1020.log
new file mode 100644 (file)
index 0000000..ba28456
--- /dev/null
@@ -0,0 +1,67 @@
+Bus 002 Device 008: ID 21e7:000e
+Device Descriptor:
+  bLength                18
+  bDescriptorType         1
+  bcdUSB               2.00
+  bDeviceClass          255 Vendor Specific Class
+  bDeviceSubClass         0
+  bDeviceProtocol         0
+  bMaxPacketSize0        64
+  idVendor           0x21e7
+  idProduct          0x000e
+  bcdDevice            1.00
+  iManufacturer           1 actions
+  iProduct                2 Usb Device
+  iSerial                 3 00000000000000000000000000000000
+  bNumConfigurations      1
+  Configuration Descriptor:
+    bLength                 9
+    bDescriptorType         2
+    wTotalLength           32
+    bNumInterfaces          1
+    bConfigurationValue     2
+    iConfiguration          6 PICO PROJECTOR
+    bmAttributes         0xc0
+      Self Powered
+    MaxPower                2mA
+    Interface Descriptor:
+      bLength                 9
+      bDescriptorType         4
+      bInterfaceNumber        0
+      bAlternateSetting       0
+      bNumEndpoints           2
+      bInterfaceClass       255 Vendor Specific Class
+      bInterfaceSubClass      8
+      bInterfaceProtocol      8
+      iInterface              7 USB PICO
+      Endpoint Descriptor:
+        bLength                 7
+        bDescriptorType         5
+        bEndpointAddress     0x81  EP 1 IN
+        bmAttributes            2
+          Transfer Type            Bulk
+          Synch Type               None
+          Usage Type               Data
+        wMaxPacketSize     0x0200  1x 512 bytes
+        bInterval               0
+      Endpoint Descriptor:
+        bLength                 7
+        bDescriptorType         5
+        bEndpointAddress     0x01  EP 1 OUT
+        bmAttributes            2
+          Transfer Type            Bulk
+          Synch Type               None
+          Usage Type               Data
+        wMaxPacketSize     0x0200  1x 512 bytes
+        bInterval               1
+Device Qualifier (for other device speed):
+  bLength                10
+  bDescriptorType         6
+  bcdUSB               2.00
+  bDeviceClass            0 (Defined at Interface level)
+  bDeviceSubClass         0
+  bDeviceProtocol         0
+  bMaxPacketSize0        64
+  bNumConfigurations      1
+Device Status:     0x0001
+  Self Powered
index c77a812..c563f5f 100644 (file)
@@ -18,8 +18,8 @@ endif()
 option(BUILD_AM7XXX-PLAY "Build a more complete example: am7xxx-play" TRUE)
 if(BUILD_AM7XXX-PLAY)
   find_package(FFmpeg REQUIRED)
-  set(CMAKE_REQUIRED_LIBRARIES ${FFMPEG_LIBRARIES}) 
-  set(CMAKE_REQUIRED_INCLUDES ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) 
+  set(CMAKE_REQUIRED_LIBRARIES ${FFMPEG_LIBRARIES})
+  set(CMAKE_REQUIRED_INCLUDES ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS})
   check_symbol_exists(avformat_open_input
     "${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}/libavformat/avformat.h"
     HAVE_AVFORMAT_OPEN_INPUT)
@@ -50,6 +50,7 @@ if(BUILD_AM7XXX-PLAY)
   if (XCB_FOUND)
     add_definitions("${LIBXCB_DEFINITIONS} -DHAVE_XCB")
     include_directories(${LIBXCB_INCLUDE_DIRS})
+    set(OPTIONAL_LIBRARIES ${LIBXCB_LIBRARIES})
   endif()
 
   add_executable(am7xxx-play am7xxx-play.c)
@@ -57,7 +58,7 @@ if(BUILD_AM7XXX-PLAY)
   target_link_libraries(am7xxx-play am7xxx
     ${FFMPEG_LIBRARIES}
     ${FFMPEG_LIBSWSCALE_LIBRARIES}
-    ${LIBXCB_LIBRARIES})
+    ${OPTIONAL_LIBRARIES})
   install(TARGETS am7xxx-play
     DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
 endif()
index a66c37d..793130e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -17,6 +17,7 @@
  */
 
 #include <stdio.h>
+#include <string.h>
 #include <errno.h>
 #include <libusb.h>
 
 
 static unsigned char switch_command[] =
        "\x55\x53\x42\x43\x08\x70\x52\x89\x00\x00\x00\x00\x00\x00"
-       "\x0c\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+       "\x10\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
 
 int main(void)
 {
        int ret;
-       int transferred;
-       libusb_device_handle *usb_device = NULL;
-
+       libusb_device_handle *usb_device;
+       int current_configuration;
        unsigned int len;
+       int transferred;
 
        ret = libusb_init(NULL);
-       if (ret < 0)
+       if (ret < 0) {
+               fprintf(stderr, "libusb_init failed: %s\n",
+                       libusb_error_name(ret));
                goto out;
+       }
 
-       libusb_set_debug(NULL, 3);
+       libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_INFO);
 
        usb_device = libusb_open_device_with_vid_pid(NULL,
                                                     AM7XXX_STORAGE_VID,
                                                     AM7XXX_STORAGE_PID);
        if (usb_device == NULL) {
-               fprintf(stderr, "cannot open the device: %d.\n", errno);
+               fprintf(stderr, "libusb_open failed: %s\n", strerror(errno));
                ret = -errno;
                goto out;
        }
 
-       if (libusb_kernel_driver_active(usb_device, AM7XXX_STORAGE_INTERFACE)) {
-               ret = libusb_detach_kernel_driver(usb_device,
-                                                 AM7XXX_STORAGE_INTERFACE);
-               if (ret < 0)
-                       fprintf(stderr, "Warning: cannot detach kernel driver.\n");
-       } else {
-               fprintf(stderr, "kernel driver not active.\n");
-       }
-
-       ret = libusb_set_configuration(usb_device, AM7XXX_STORAGE_CONFIGURATION);
+       current_configuration = -1;
+       ret = libusb_get_configuration(usb_device, &current_configuration);
        if (ret < 0) {
-               fprintf(stderr, "cannot set configuration.\n");
+               fprintf(stderr, "libusb_get_configuration failed: %s\n",
+                       libusb_error_name(ret));
                goto out_libusb_close;
        }
 
+       if (current_configuration != AM7XXX_STORAGE_CONFIGURATION) {
+               ret = libusb_set_configuration(usb_device,
+                                              AM7XXX_STORAGE_CONFIGURATION);
+               if (ret < 0) {
+                       fprintf(stderr, "libusb_set_configuration failed: %s\n",
+                               libusb_error_name(ret));
+                       fprintf(stderr, "Cannot set configuration %d\n",
+                               AM7XXX_STORAGE_CONFIGURATION);
+                       goto out_libusb_close;
+               }
+       }
+
+       libusb_set_auto_detach_kernel_driver(usb_device, 1);
+
        ret = libusb_claim_interface(usb_device, AM7XXX_STORAGE_INTERFACE);
        if (ret < 0) {
-               fprintf(stderr, "cannot claim interface.\n");
+               fprintf(stderr, "libusb_claim_interface failed: %s\n",
+                       libusb_error_name(ret));
+               fprintf(stderr, "Cannot claim interface %d\n",
+                       AM7XXX_STORAGE_INTERFACE);
                goto out_libusb_close;
        }
 
+       /* Checking that the configuration has not changed, as suggested in
+        * http://libusb.sourceforge.net/api-1.0/caveats.html
+        */
+       current_configuration = -1;
+       ret = libusb_get_configuration(usb_device, &current_configuration);
+       if (ret < 0) {
+               fprintf(stderr, "libusb_get_configuration after claim failed: %s\n",
+                       libusb_error_name(ret));
+               goto out_libusb_release_interface;
+       }
+
+       if (current_configuration != AM7XXX_STORAGE_CONFIGURATION) {
+               fprintf(stderr, "libusb configuration changed (expected: %d, current: %d\n",
+                       AM7XXX_STORAGE_CONFIGURATION, current_configuration);
+               ret = -EINVAL;
+               goto out_libusb_release_interface;
+       }
+
        len = sizeof(switch_command);
+
        transferred = 0;
        ret = libusb_bulk_transfer(usb_device, AM7XXX_STORAGE_OUT_EP,
                                   switch_command, len, &transferred, 0);
index 2fa615a..6b0d206 100644 (file)
@@ -216,7 +216,7 @@ static int video_output_init(struct video_output_ctx *output_ctx,
         */
        if (image_format == AM7XXX_IMAGE_FORMAT_NV12) {
                fprintf(stdout, "using raw output format\n");
-               output_codec_ctx->pix_fmt    = PIX_FMT_NV12;
+               output_codec_ctx->pix_fmt    = AV_PIX_FMT_NV12;
                output_ctx->codec_ctx = output_codec_ctx;
                output_ctx->raw_output = 1;
                ret = 0;
@@ -235,8 +235,8 @@ static int video_output_init(struct video_output_ctx *output_ctx,
         * in particular they won't be 0, this is needed because they are used
         * as divisor somewhere in the encoding process */
        output_codec_ctx->qmin       = output_codec_ctx->qmax = ((100 - (quality - 1)) * FF_QUALITY_SCALE) / 100;
-       output_codec_ctx->mb_lmin    = output_codec_ctx->lmin = output_codec_ctx->qmin * FF_QP2LAMBDA;
-       output_codec_ctx->mb_lmax    = output_codec_ctx->lmax = output_codec_ctx->qmax * FF_QP2LAMBDA;
+       output_codec_ctx->mb_lmin    = output_codec_ctx->qmin * FF_QP2LAMBDA;
+       output_codec_ctx->mb_lmax    = output_codec_ctx->qmax * FF_QP2LAMBDA;
        output_codec_ctx->flags      |= CODEC_FLAG_QSCALE;
        output_codec_ctx->global_quality = output_codec_ctx->qmin * FF_QP2LAMBDA;
 
@@ -276,7 +276,8 @@ static int am7xxx_play(const char *input_format_string,
                       unsigned int upscale,
                       unsigned int quality,
                       am7xxx_image_format image_format,
-                      am7xxx_device *dev)
+                      am7xxx_device *dev,
+                      int dump_frame)
 {
        struct video_input_ctx input_ctx;
        struct video_output_ctx output_ctx;
@@ -320,6 +321,9 @@ static int am7xxx_play(const char *input_format_string,
                ret = -ENOMEM;
                goto cleanup_picture_raw;
        }
+       picture_scaled->format = (output_ctx.codec_ctx)->pix_fmt;
+       picture_scaled->width = (output_ctx.codec_ctx)->width;
+       picture_scaled->height = (output_ctx.codec_ctx)->height;
 
        /* calculate the bytes needed for the output image and create buffer for the output image */
        out_buf_size = avpicture_get_size((output_ctx.codec_ctx)->pix_fmt,
@@ -354,6 +358,7 @@ static int am7xxx_play(const char *input_format_string,
                goto cleanup_out_buf;
        }
 
+       got_packet = 0;
        while (run) {
                /* read packet */
                ret = av_read_frame(input_ctx.format_ctx, &in_packet);
@@ -381,11 +386,11 @@ static int am7xxx_play(const char *input_format_string,
                        goto end_while;
                }
 
-               /* if we get the complete frame */
+               /* if we got the complete frame */
                if (got_picture) {
                        /* convert it to YUV */
                        sws_scale(sw_scale_ctx,
-                                 (const uint8_t * const*)picture_raw->data,
+                                 (const uint8_t * const *)picture_raw->data,
                                  picture_raw->linesize,
                                  0,
                                  (input_ctx.codec_ctx)->height,
@@ -416,15 +421,19 @@ static int am7xxx_play(const char *input_format_string,
                        }
 
 #ifdef DEBUG
-                       char filename[NAME_MAX];
-                       FILE *file;
-                       if (!output_ctx.raw_output)
-                               snprintf(filename, NAME_MAX, "out_q%03d.jpg", quality);
-                       else
-                               snprintf(filename, NAME_MAX, "out.raw");
-                       file = fopen(filename, "wb");
-                       fwrite(out_picture, 1, out_picture_size, file);
-                       fclose(file);
+                       if (dump_frame) {
+                               char filename[NAME_MAX];
+                               FILE *file;
+                               if (!output_ctx.raw_output)
+                                       snprintf(filename, NAME_MAX, "out_q%03d.jpg", quality);
+                               else
+                                       snprintf(filename, NAME_MAX, "out.raw");
+                               file = fopen(filename, "wb");
+                               fwrite(out_picture, 1, out_picture_size, file);
+                               fclose(file);
+                       }
+#else
+                       (void) dump_frame;
 #endif
 
                        ret = am7xxx_send_image_async(dev,
@@ -434,7 +443,7 @@ static int am7xxx_play(const char *input_format_string,
                                                      out_picture,
                                                      out_picture_size);
                        if (ret < 0) {
-                               perror("am7xxx_send_image");
+                               perror("am7xxx_send_image_async");
                                run = 0;
                                goto end_while;
                        }
@@ -593,6 +602,9 @@ static void usage(char *name)
        printf("usage: %s [OPTIONS]\n\n", name);
        printf("OPTIONS:\n");
        printf("\t-d <index>\t\tthe device index (default is 0)\n");
+#ifdef DEBUG
+       printf("\t-D \t\t\tdump the last frame to a file (only active in DEBUG mode)\n");
+#endif
        printf("\t-f <input format>\tthe input device format\n");
        printf("\t-i <input path>\t\tthe input path\n");
        printf("\t-o <options>\t\ta comma separated list of input format options\n");
@@ -640,8 +652,9 @@ int main(int argc, char *argv[])
        int format = AM7XXX_IMAGE_FORMAT_JPEG;
        am7xxx_context *ctx;
        am7xxx_device *dev;
+       int dump_frame = 0;
 
-       while ((opt = getopt(argc, argv, "d:f:i:o:s:uF:q:l:p:z:h")) != -1) {
+       while ((opt = getopt(argc, argv, "d:Df:i:o:s:uF:q:l:p:z:h")) != -1) {
                switch (opt) {
                case 'd':
                        device_index = atoi(optarg);
@@ -651,6 +664,12 @@ int main(int argc, char *argv[])
                                goto out;
                        }
                        break;
+               case 'D':
+                       dump_frame = 1;
+#ifndef DEBUG
+                       fprintf(stderr, "Warning: the -D option is only active in DEBUG mode.\n");
+#endif
+                       break;
                case 'f':
                        input_format_string = strdup(optarg);
                        break;
@@ -849,7 +868,8 @@ int main(int argc, char *argv[])
                          upscale,
                          quality,
                          format,
-                         dev);
+                         dev,
+                         dump_frame);
        if (ret < 0) {
                fprintf(stderr, "am7xxx_play failed\n");
                goto cleanup;
index d335ed1..2069799 100644 (file)
@@ -4,7 +4,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
index ebc403e..76df87d 100644 (file)
@@ -34,7 +34,7 @@
  * taken from: http://unixwiz.net/techtips/gnu-c-attributes.html)
  */
 #ifndef __GNUC__
-#  define  __attribute__(x)  /*NOTHING*/
+#  define  __attribute__(x)  /* NOTHING */
 #endif
 
 /* Control shared library symbols visibility */
@@ -53,7 +53,7 @@
 
 static void log_message(am7xxx_context *ctx,
                        int level,
-                       const char *function,
+                       const char *function_name,
                        int line,
                        const char *fmt,
                        ...) __attribute__ ((format (printf, 5, 6)));
@@ -341,7 +341,7 @@ static inline unsigned int in_80chars(unsigned int i)
 {
        /* The 3 below is the length of "xx " where xx is the hex string
         * representation of a byte */
-       return ((i+1) % (80/3));
+       return ((i + 1) % (80 / 3));
 }
 
 static void trace_dump_buffer(am7xxx_context *ctx, const char *message,
@@ -381,12 +381,13 @@ static void trace_dump_buffer(am7xxx_context *ctx, const char *message,
 static int read_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len)
 {
        int ret;
-       int transferred = 0;
+       int transferred;
 
+       transferred = 0;
        ret = libusb_bulk_transfer(dev->usb_device, 0x81, buffer, len, &transferred, 0);
        if (ret != 0 || (unsigned int)transferred != len) {
-               error(dev->ctx, "ret: %d\ttransferred: %d (expected %u)\n",
-                     ret, transferred, len);
+               error(dev->ctx, "%s. Transferred: %d (expected %u)\n",
+                     libusb_error_name(ret), transferred, len);
                return ret;
        }
 
@@ -398,14 +399,15 @@ static int read_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len)
 static int send_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len)
 {
        int ret;
-       int transferred = 0;
+       int transferred;
 
        trace_dump_buffer(dev->ctx, "sending -->", buffer, len);
 
+       transferred = 0;
        ret = libusb_bulk_transfer(dev->usb_device, 0x1, buffer, len, &transferred, 0);
        if (ret != 0 || (unsigned int)transferred != len) {
-               error(dev->ctx, "ret: %d\ttransferred: %d (expected %u)\n",
-                     ret, transferred, len);
+               error(dev->ctx, "%s. Transferred: %d (expected %u)\n",
+                     libusb_error_name(ret), transferred, len);
                return ret;
        }
 
@@ -489,8 +491,8 @@ static int send_data_async(am7xxx_device *dev, uint8_t *buffer, unsigned int len
 
        /* Make a copy of the buffer so the caller can safely reuse it just
         * after libusb_submit_transfer() has returned. This technique
-        * requires more allocations than a proper double-buffering approach
-        * but it takes a lot less code. */
+        * requires more dynamic allocations compared to a proper
+        * double-buffering approach but it takes a lot less code. */
        transfer_buffer = malloc(len);
        if (transfer_buffer == NULL) {
                error(dev->ctx, "cannot allocate transfer buffer (%s)\n",
@@ -626,7 +628,7 @@ static int send_command(am7xxx_device *dev, am7xxx_packet_type type)
  * set up */
 static void log_message(am7xxx_context *ctx,
                        int level,
-                       const char *function,
+                       const char *function_name,
                        int line,
                        const char *fmt,
                        ...)
@@ -634,8 +636,8 @@ static void log_message(am7xxx_context *ctx,
        va_list ap;
 
        if (level == AM7XXX_LOG_FATAL || (ctx && level <= ctx->log_level)) {
-               if (function) {
-                       fprintf(stderr, "%s", function);
+               if (function_name) {
+                       fprintf(stderr, "%s", function_name);
                        if (line)
                                fprintf(stderr, "[%d]", line);
                        fprintf(stderr, ": ");
@@ -662,7 +664,7 @@ static am7xxx_device *add_new_device(am7xxx_context *ctx,
 
        new_device = malloc(sizeof(*new_device));
        if (new_device == NULL) {
-               fatal("cannot allocate a new device (%s)\n", strerror(errno));
+               debug(ctx, "cannot allocate a new device (%s)\n", strerror(errno));
                return NULL;
        }
        memset(new_device, 0, sizeof(*new_device));
@@ -702,6 +704,119 @@ static am7xxx_device *find_device(am7xxx_context *ctx,
        return current;
 }
 
+static int open_device(am7xxx_context *ctx,
+                      unsigned int device_index,
+                      libusb_device *usb_dev,
+                      am7xxx_device **dev)
+{
+       int ret;
+       int current_configuration;
+
+       *dev = find_device(ctx, device_index);
+       if (*dev == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* the usb device has already been opened */
+       if ((*dev)->usb_device) {
+               ret = 1;
+               goto out;
+       }
+
+       ret = libusb_open(usb_dev, &((*dev)->usb_device));
+       if (ret < 0) {
+               debug(ctx, "libusb_open failed: %s\n", libusb_error_name(ret));
+               goto out;
+       }
+
+       /* XXX, the device is now open, if any of the calls below fail we need
+        * to close it again before bailing out.
+        */
+
+       current_configuration = -1;
+       ret = libusb_get_configuration((*dev)->usb_device,
+                                      &current_configuration);
+       if (ret < 0) {
+               debug(ctx, "libusb_get_configuration failed: %s\n",
+                     libusb_error_name(ret));
+               goto out_libusb_close;
+       }
+
+       if (current_configuration != (*dev)->desc->configuration) {
+               /*
+                * In principle, before setting a new configuration, kernel
+                * drivers should be detached from _all_ interfaces; for
+                * example calling something like the following "invented"
+                * function _before_ setting the new configuration:
+                *
+                *   libusb_detach_all_kernel_drivers((*dev)->usb_device);
+                *
+                * However, in practice, this is not necessary for most
+                * devices as they have only one configuration.
+                *
+                * When a device only has one configuration:
+                *
+                *   - if there was a kernel driver bound to the device, it
+                *     had already set the configuration and the call below
+                *     will be skipped;
+                *
+                *   - if no kernel driver was bound to the device, the call
+                *     below will suceed.
+                */
+               ret = libusb_set_configuration((*dev)->usb_device,
+                                              (*dev)->desc->configuration);
+               if (ret < 0) {
+                       debug(ctx, "libusb_set_configuration failed: %s\n",
+                             libusb_error_name(ret));
+                       debug(ctx, "Cannot set configuration %hhu\n",
+                             (*dev)->desc->configuration);
+                       goto out_libusb_close;
+               }
+       }
+
+       libusb_set_auto_detach_kernel_driver((*dev)->usb_device, 1);
+
+       ret = libusb_claim_interface((*dev)->usb_device,
+                                    (*dev)->desc->interface_number);
+       if (ret < 0) {
+               debug(ctx, "libusb_claim_interface failed: %s\n",
+                     libusb_error_name(ret));
+               debug(ctx, "Cannot claim interface %hhu\n",
+                     (*dev)->desc->interface_number);
+               goto out_libusb_close;
+       }
+
+       /* Checking that the configuration has not changed, as suggested in
+        * http://libusb.sourceforge.net/api-1.0/caveats.html
+        */
+       current_configuration = -1;
+       ret = libusb_get_configuration((*dev)->usb_device,
+                                      &current_configuration);
+       if (ret < 0) {
+               debug(ctx, "libusb_get_configuration after claim failed: %s\n",
+                     libusb_error_name(ret));
+               goto out_libusb_release_interface;
+       }
+
+       if (current_configuration != (*dev)->desc->configuration) {
+               debug(ctx, "libusb configuration changed (expected: %hhu, current: %d\n",
+                     (*dev)->desc->configuration, current_configuration);
+               ret = -EINVAL;
+               goto out_libusb_release_interface;
+       }
+out:
+       return ret;
+
+out_libusb_release_interface:
+       libusb_release_interface((*dev)->usb_device,
+                                (*dev)->desc->interface_number);
+out_libusb_close:
+       libusb_close((*dev)->usb_device);
+       (*dev)->usb_device = NULL;
+       return ret;
+}
+
 typedef enum {
        SCAN_OP_BUILD_DEVLIST,
        SCAN_OP_OPEN_DEVICE,
@@ -711,13 +826,14 @@ typedef enum {
  * This is where the central logic of multi-device support is.
  *
  * When 'op' == SCAN_OP_BUILD_DEVLIST the parameters 'open_device_index' and
- * 'dev' are ignored; the function returns 0 on success and a negative value
+ * 'dev' are ignored; the function returns 0 on success or a negative value
  * on error.
  *
  * When 'op' == SCAN_OP_OPEN_DEVICE the function opens the supported USB
  * device with index 'open_device_index' and returns the correspondent
- * am7xxx_device in the 'dev' parameter; the function returns 0 on success,
- * 1 if the device was already open and a negative value on error.
+ * am7xxx_device in the 'dev' parameter; the function returns the value from
+ * open_device(), which is 0 on success, 1 if the device was already open or
+ * a negative value on error.
  *
  * NOTES:
  * if scan_devices() fails when called with 'op' == SCAN_OP_BUILD_DEVLIST,
@@ -728,7 +844,7 @@ static int scan_devices(am7xxx_context *ctx, scan_op op,
                        unsigned int open_device_index, am7xxx_device **dev)
 {
        ssize_t num_devices;
-       libusb_device** list;
+       libusb_device **list;
        unsigned int current_index;
        int i;
        int ret;
@@ -780,51 +896,16 @@ static int scan_devices(am7xxx_context *ctx, scan_op op,
                                } else if (op == SCAN_OP_OPEN_DEVICE &&
                                           current_index == open_device_index) {
 
-                                       *dev = find_device(ctx, open_device_index);
-                                       if (*dev == NULL) {
-                                               ret = -ENODEV;
-                                               goto out;
-                                       }
-
-                                       /* the usb device has already been opened */
-                                       if ((*dev)->usb_device) {
-                                               debug(ctx, "(*dev)->usb_device already set\n");
-                                               ret = 1;
-                                               goto out;
-                                       }
-
-                                       ret = libusb_open(list[i], &((*dev)->usb_device));
-                                       if (ret < 0) {
-                                               debug(ctx, "libusb_open failed\n");
-                                               goto out;
-                                       }
-
-                                       /* XXX, the device is now open, if any
-                                        * of the calls below fail we need to
-                                        * close it again before bailing out.
-                                        */
-
-                                       ret = libusb_set_configuration((*dev)->usb_device,
-                                                                      (*dev)->desc->configuration);
-                                       if (ret < 0) {
-                                               debug(ctx, "libusb_set_configuration failed\n");
-                                               debug(ctx, "Cannot set configuration %hhu\n",
-                                                     (*dev)->desc->configuration);
-                                               goto out_libusb_close;
-                                       }
-
-                                       ret = libusb_claim_interface((*dev)->usb_device,
-                                                                    (*dev)->desc->interface_number);
-                                       if (ret < 0) {
-                                               debug(ctx, "libusb_claim_interface failed\n");
-                                               debug(ctx, "Cannot claim interface %hhu\n",
-                                                     (*dev)->desc->interface_number);
-out_libusb_close:
-                                               libusb_close((*dev)->usb_device);
-                                               (*dev)->usb_device = NULL;
-                                               goto out;
-                                       }
+                                       ret = open_device(ctx,
+                                                         open_device_index,
+                                                         list[i],
+                                                         dev);
+                                       if (ret < 0)
+                                               debug(ctx, "open_device failed\n");
 
+                                       /* exit the loop unconditionally after
+                                        * attempting to open the device
+                                        * requested by the user */
                                        goto out;
                                }
                                current_index++;
@@ -832,7 +913,8 @@ out_libusb_close:
                }
        }
 
-       /* if we made it up to here we didn't find any device to open */
+       /* if we made it up to here when op == SCAN_OP_OPEN_DEVICE,
+        * no devices to open had been found. */
        if (op == SCAN_OP_OPEN_DEVICE) {
                error(ctx, "Cannot find any device to open\n");
                ret = -ENODEV;
@@ -1020,8 +1102,10 @@ AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx)
        (*ctx)->log_level = AM7XXX_LOG_TRACE;
 
        ret = libusb_init(&((*ctx)->usb_context));
-       if (ret < 0)
+       if (ret < 0) {
+               error(*ctx, "libusb_init failed: %s\n", libusb_error_name(ret));
                goto out_free_context;
+       }
 
        libusb_set_debug((*ctx)->usb_context, LIBUSB_LOG_LEVEL_INFO);
 
index 4a97f69..d103c22 100644 (file)
@@ -252,7 +252,7 @@ int am7xxx_send_image(am7xxx_device *dev,
  * This is the function that actually makes the device display something.
  * Static pictures can be sent just once and the device will keep showing them
  * until another image get sent or some command resets or turns off the display.
- * 
+ *
  * @note This _async() variant makes a copy of the image buffer, so the caller
  * is free to reuse the buffer just after the function returns.
  *
index 1741f18..6bc9a73 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Public domain, stripped down version of:
  * https://gist.github.com/panzi/6856583
  */