LCOV - code coverage report
Current view: top level - fftools - ffmpeg_hw.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 30 264 11.4 %
Date: 2017-12-14 19:11:59 Functions: 5 12 41.7 %

          Line data    Source code
       1             : /*
       2             :  * This file is part of FFmpeg.
       3             :  *
       4             :  * FFmpeg is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Lesser General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2.1 of the License, or (at your option) any later version.
       8             :  *
       9             :  * FFmpeg is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Lesser General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public
      15             :  * License along with FFmpeg; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      17             :  */
      18             : 
      19             : #include <string.h>
      20             : 
      21             : #include "libavutil/avstring.h"
      22             : 
      23             : #include "ffmpeg.h"
      24             : 
      25             : static int nb_hw_devices;
      26             : static HWDevice **hw_devices;
      27             : 
      28         778 : static HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
      29             : {
      30         778 :     HWDevice *found = NULL;
      31             :     int i;
      32         778 :     for (i = 0; i < nb_hw_devices; i++) {
      33           0 :         if (hw_devices[i]->type == type) {
      34           0 :             if (found)
      35           0 :                 return NULL;
      36           0 :             found = hw_devices[i];
      37             :         }
      38             :     }
      39         778 :     return found;
      40             : }
      41             : 
      42           0 : HWDevice *hw_device_get_by_name(const char *name)
      43             : {
      44             :     int i;
      45           0 :     for (i = 0; i < nb_hw_devices; i++) {
      46           0 :         if (!strcmp(hw_devices[i]->name, name))
      47           0 :             return hw_devices[i];
      48             :     }
      49           0 :     return NULL;
      50             : }
      51             : 
      52           0 : static HWDevice *hw_device_add(void)
      53             : {
      54             :     int err;
      55           0 :     err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
      56             :                             sizeof(*hw_devices));
      57           0 :     if (err) {
      58           0 :         nb_hw_devices = 0;
      59           0 :         return NULL;
      60             :     }
      61           0 :     hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
      62           0 :     if (!hw_devices[nb_hw_devices])
      63           0 :         return NULL;
      64           0 :     return hw_devices[nb_hw_devices++];
      65             : }
      66             : 
      67           0 : static char *hw_device_default_name(enum AVHWDeviceType type)
      68             : {
      69             :     // Make an automatic name of the form "type%d".  We arbitrarily
      70             :     // limit at 1000 anonymous devices of the same type - there is
      71             :     // probably something else very wrong if you get to this limit.
      72           0 :     const char *type_name = av_hwdevice_get_type_name(type);
      73             :     char *name;
      74             :     size_t index_pos;
      75           0 :     int index, index_limit = 1000;
      76           0 :     index_pos = strlen(type_name);
      77           0 :     name = av_malloc(index_pos + 4);
      78           0 :     if (!name)
      79           0 :         return NULL;
      80           0 :     for (index = 0; index < index_limit; index++) {
      81           0 :         snprintf(name, index_pos + 4, "%s%d", type_name, index);
      82           0 :         if (!hw_device_get_by_name(name))
      83           0 :             break;
      84             :     }
      85           0 :     if (index >= index_limit) {
      86           0 :         av_freep(&name);
      87           0 :         return NULL;
      88             :     }
      89           0 :     return name;
      90             : }
      91             : 
      92           0 : int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
      93             : {
      94             :     // "type=name:device,key=value,key2=value2"
      95             :     // "type:device,key=value,key2=value2"
      96             :     // -> av_hwdevice_ctx_create()
      97             :     // "type=name@name"
      98             :     // "type@name"
      99             :     // -> av_hwdevice_ctx_create_derived()
     100             : 
     101           0 :     AVDictionary *options = NULL;
     102           0 :     char *type_name = NULL, *name = NULL, *device = NULL;
     103             :     enum AVHWDeviceType type;
     104             :     HWDevice *dev, *src;
     105           0 :     AVBufferRef *device_ref = NULL;
     106             :     int err;
     107             :     const char *errmsg, *p, *q;
     108             :     size_t k;
     109             : 
     110           0 :     k = strcspn(arg, ":=@");
     111           0 :     p = arg + k;
     112             : 
     113           0 :     type_name = av_strndup(arg, k);
     114           0 :     if (!type_name) {
     115           0 :         err = AVERROR(ENOMEM);
     116           0 :         goto fail;
     117             :     }
     118           0 :     type = av_hwdevice_find_type_by_name(type_name);
     119           0 :     if (type == AV_HWDEVICE_TYPE_NONE) {
     120           0 :         errmsg = "unknown device type";
     121           0 :         goto invalid;
     122             :     }
     123             : 
     124           0 :     if (*p == '=') {
     125           0 :         k = strcspn(p + 1, ":@");
     126             : 
     127           0 :         name = av_strndup(p + 1, k);
     128           0 :         if (!name) {
     129           0 :             err = AVERROR(ENOMEM);
     130           0 :             goto fail;
     131             :         }
     132           0 :         if (hw_device_get_by_name(name)) {
     133           0 :             errmsg = "named device already exists";
     134           0 :             goto invalid;
     135             :         }
     136             : 
     137           0 :         p += 1 + k;
     138             :     } else {
     139           0 :         name = hw_device_default_name(type);
     140           0 :         if (!name) {
     141           0 :             err = AVERROR(ENOMEM);
     142           0 :             goto fail;
     143             :         }
     144             :     }
     145             : 
     146           0 :     if (!*p) {
     147             :         // New device with no parameters.
     148           0 :         err = av_hwdevice_ctx_create(&device_ref, type,
     149             :                                      NULL, NULL, 0);
     150           0 :         if (err < 0)
     151           0 :             goto fail;
     152             : 
     153           0 :     } else if (*p == ':') {
     154             :         // New device with some parameters.
     155           0 :         ++p;
     156           0 :         q = strchr(p, ',');
     157           0 :         if (q) {
     158           0 :             device = av_strndup(p, q - p);
     159           0 :             if (!device) {
     160           0 :                 err = AVERROR(ENOMEM);
     161           0 :                 goto fail;
     162             :             }
     163           0 :             err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
     164           0 :             if (err < 0) {
     165           0 :                 errmsg = "failed to parse options";
     166           0 :                 goto invalid;
     167             :             }
     168             :         }
     169             : 
     170           0 :         err = av_hwdevice_ctx_create(&device_ref, type,
     171           0 :                                      device ? device : p, options, 0);
     172           0 :         if (err < 0)
     173           0 :             goto fail;
     174             : 
     175           0 :     } else if (*p == '@') {
     176             :         // Derive from existing device.
     177             : 
     178           0 :         src = hw_device_get_by_name(p + 1);
     179           0 :         if (!src) {
     180           0 :             errmsg = "invalid source device name";
     181           0 :             goto invalid;
     182             :         }
     183             : 
     184           0 :         err = av_hwdevice_ctx_create_derived(&device_ref, type,
     185             :                                              src->device_ref, 0);
     186           0 :         if (err < 0)
     187           0 :             goto fail;
     188             :     } else {
     189           0 :         errmsg = "parse error";
     190           0 :         goto invalid;
     191             :     }
     192             : 
     193           0 :     dev = hw_device_add();
     194           0 :     if (!dev) {
     195           0 :         err = AVERROR(ENOMEM);
     196           0 :         goto fail;
     197             :     }
     198             : 
     199           0 :     dev->name = name;
     200           0 :     dev->type = type;
     201           0 :     dev->device_ref = device_ref;
     202             : 
     203           0 :     if (dev_out)
     204           0 :         *dev_out = dev;
     205             : 
     206           0 :     name = NULL;
     207           0 :     err = 0;
     208           0 : done:
     209           0 :     av_freep(&type_name);
     210           0 :     av_freep(&name);
     211           0 :     av_freep(&device);
     212           0 :     av_dict_free(&options);
     213           0 :     return err;
     214           0 : invalid:
     215           0 :     av_log(NULL, AV_LOG_ERROR,
     216             :            "Invalid device specification \"%s\": %s\n", arg, errmsg);
     217           0 :     err = AVERROR(EINVAL);
     218           0 :     goto done;
     219           0 : fail:
     220           0 :     av_log(NULL, AV_LOG_ERROR,
     221             :            "Device creation failed: %d.\n", err);
     222           0 :     av_buffer_unref(&device_ref);
     223           0 :     goto done;
     224             : }
     225             : 
     226           0 : static int hw_device_init_from_type(enum AVHWDeviceType type,
     227             :                                     const char *device,
     228             :                                     HWDevice **dev_out)
     229             : {
     230           0 :     AVBufferRef *device_ref = NULL;
     231             :     HWDevice *dev;
     232             :     char *name;
     233             :     int err;
     234             : 
     235           0 :     name = hw_device_default_name(type);
     236           0 :     if (!name) {
     237           0 :         err = AVERROR(ENOMEM);
     238           0 :         goto fail;
     239             :     }
     240             : 
     241           0 :     err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
     242           0 :     if (err < 0) {
     243           0 :         av_log(NULL, AV_LOG_ERROR,
     244             :                "Device creation failed: %d.\n", err);
     245           0 :         goto fail;
     246             :     }
     247             : 
     248           0 :     dev = hw_device_add();
     249           0 :     if (!dev) {
     250           0 :         err = AVERROR(ENOMEM);
     251           0 :         goto fail;
     252             :     }
     253             : 
     254           0 :     dev->name = name;
     255           0 :     dev->type = type;
     256           0 :     dev->device_ref = device_ref;
     257             : 
     258           0 :     if (dev_out)
     259           0 :         *dev_out = dev;
     260             : 
     261           0 :     return 0;
     262             : 
     263           0 : fail:
     264           0 :     av_freep(&name);
     265           0 :     av_buffer_unref(&device_ref);
     266           0 :     return err;
     267             : }
     268             : 
     269        5411 : void hw_device_free_all(void)
     270             : {
     271             :     int i;
     272        5411 :     for (i = 0; i < nb_hw_devices; i++) {
     273           0 :         av_freep(&hw_devices[i]->name);
     274           0 :         av_buffer_unref(&hw_devices[i]->device_ref);
     275           0 :         av_freep(&hw_devices[i]);
     276             :     }
     277        5411 :     av_freep(&hw_devices);
     278        5411 :     nb_hw_devices = 0;
     279        5411 : }
     280             : 
     281       10652 : static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
     282             : {
     283             :     const AVCodecHWConfig *config;
     284             :     HWDevice *dev;
     285             :     int i;
     286       11430 :     for (i = 0;; i++) {
     287       12208 :         config = avcodec_get_hw_config(codec, i);
     288       11430 :         if (!config)
     289       10652 :             return NULL;
     290         778 :         if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
     291           0 :             continue;
     292         778 :         dev = hw_device_get_by_type(config->device_type);
     293         778 :         if (dev)
     294           0 :             return dev;
     295             :     }
     296             : }
     297             : 
     298        5323 : int hw_device_setup_for_decode(InputStream *ist)
     299             : {
     300             :     const AVCodecHWConfig *config;
     301             :     enum AVHWDeviceType type;
     302        5323 :     HWDevice *dev = NULL;
     303        5323 :     int err, auto_device = 0;
     304             : 
     305        5323 :     if (ist->hwaccel_device) {
     306           0 :         dev = hw_device_get_by_name(ist->hwaccel_device);
     307           0 :         if (!dev) {
     308           0 :             if (ist->hwaccel_id == HWACCEL_AUTO) {
     309           0 :                 auto_device = 1;
     310           0 :             } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
     311           0 :                 type = ist->hwaccel_device_type;
     312           0 :                 err = hw_device_init_from_type(type, ist->hwaccel_device,
     313             :                                                &dev);
     314             :             } else {
     315             :                 // This will be dealt with by API-specific initialisation
     316             :                 // (using hwaccel_device), so nothing further needed here.
     317           0 :                 return 0;
     318             :             }
     319             :         } else {
     320           0 :             if (ist->hwaccel_id == HWACCEL_AUTO) {
     321           0 :                 ist->hwaccel_device_type = dev->type;
     322           0 :             } else if (ist->hwaccel_device_type != dev->type) {
     323           0 :                 av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device "
     324             :                        "specified for decoder: device %s of type %s is not "
     325           0 :                        "usable with hwaccel %s.\n", dev->name,
     326           0 :                        av_hwdevice_get_type_name(dev->type),
     327             :                        av_hwdevice_get_type_name(ist->hwaccel_device_type));
     328           0 :                 return AVERROR(EINVAL);
     329             :             }
     330             :         }
     331             :     } else {
     332        5323 :         if (ist->hwaccel_id == HWACCEL_AUTO) {
     333           0 :             auto_device = 1;
     334        5323 :         } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
     335           0 :             type = ist->hwaccel_device_type;
     336           0 :             dev = hw_device_get_by_type(type);
     337           0 :             if (!dev)
     338           0 :                 err = hw_device_init_from_type(type, NULL, &dev);
     339             :         } else {
     340        5323 :             dev = hw_device_match_by_codec(ist->dec);
     341        5323 :             if (!dev) {
     342             :                 // No device for this codec, but not using generic hwaccel
     343             :                 // and therefore may well not need one - ignore.
     344        5323 :                 return 0;
     345             :             }
     346             :         }
     347             :     }
     348             : 
     349           0 :     if (auto_device) {
     350             :         int i;
     351           0 :         if (!avcodec_get_hw_config(ist->dec, 0)) {
     352             :             // Decoder does not support any hardware devices.
     353           0 :             return 0;
     354             :         }
     355           0 :         for (i = 0; !dev; i++) {
     356           0 :             config = avcodec_get_hw_config(ist->dec, i);
     357           0 :             if (!config)
     358           0 :                 break;
     359           0 :             type = config->device_type;
     360           0 :             dev = hw_device_get_by_type(type);
     361           0 :             if (dev) {
     362           0 :                 av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
     363             :                        "hwaccel type %s with existing device %s.\n",
     364           0 :                        av_hwdevice_get_type_name(type), dev->name);
     365             :             }
     366             :         }
     367           0 :         for (i = 0; !dev; i++) {
     368           0 :             config = avcodec_get_hw_config(ist->dec, i);
     369           0 :             if (!config)
     370           0 :                 break;
     371           0 :             type = config->device_type;
     372             :             // Try to make a new device of this type.
     373           0 :             err = hw_device_init_from_type(type, ist->hwaccel_device,
     374             :                                            &dev);
     375           0 :             if (err < 0) {
     376             :                 // Can't make a device of this type.
     377           0 :                 continue;
     378             :             }
     379           0 :             if (ist->hwaccel_device) {
     380           0 :                 av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
     381             :                        "hwaccel type %s with new device created "
     382             :                        "from %s.\n", av_hwdevice_get_type_name(type),
     383             :                        ist->hwaccel_device);
     384             :             } else {
     385           0 :                 av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
     386             :                        "hwaccel type %s with new default device.\n",
     387             :                        av_hwdevice_get_type_name(type));
     388             :             }
     389             :         }
     390           0 :         if (dev) {
     391           0 :             ist->hwaccel_device_type = type;
     392             :         } else {
     393           0 :             av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel "
     394             :                    "disabled: no device found.\n");
     395           0 :             ist->hwaccel_id = HWACCEL_NONE;
     396           0 :             return 0;
     397             :         }
     398             :     }
     399             : 
     400           0 :     if (!dev) {
     401           0 :         av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available "
     402             :                "for decoder: device type %s needed for codec %s.\n",
     403           0 :                av_hwdevice_get_type_name(type), ist->dec->name);
     404           0 :         return err;
     405             :     }
     406             : 
     407           0 :     ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
     408           0 :     if (!ist->dec_ctx->hw_device_ctx)
     409           0 :         return AVERROR(ENOMEM);
     410             : 
     411           0 :     return 0;
     412             : }
     413             : 
     414        5329 : int hw_device_setup_for_encode(OutputStream *ost)
     415             : {
     416             :     HWDevice *dev;
     417             : 
     418        5329 :     dev = hw_device_match_by_codec(ost->enc);
     419        5329 :     if (dev) {
     420           0 :         ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
     421           0 :         if (!ost->enc_ctx->hw_device_ctx)
     422           0 :             return AVERROR(ENOMEM);
     423           0 :         return 0;
     424             :     } else {
     425             :         // No device required, or no device available.
     426        5329 :         return 0;
     427             :     }
     428             : }
     429             : 
     430           0 : static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
     431             : {
     432           0 :     InputStream *ist = avctx->opaque;
     433           0 :     AVFrame *output = NULL;
     434           0 :     enum AVPixelFormat output_format = ist->hwaccel_output_format;
     435             :     int err;
     436             : 
     437           0 :     if (input->format == output_format) {
     438             :         // Nothing to do.
     439           0 :         return 0;
     440             :     }
     441             : 
     442           0 :     output = av_frame_alloc();
     443           0 :     if (!output)
     444           0 :         return AVERROR(ENOMEM);
     445             : 
     446           0 :     output->format = output_format;
     447             : 
     448           0 :     err = av_hwframe_transfer_data(output, input, 0);
     449           0 :     if (err < 0) {
     450           0 :         av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
     451             :                "output frame: %d.\n", err);
     452           0 :         goto fail;
     453             :     }
     454             : 
     455           0 :     err = av_frame_copy_props(output, input);
     456           0 :     if (err < 0) {
     457           0 :         av_frame_unref(output);
     458           0 :         goto fail;
     459             :     }
     460             : 
     461           0 :     av_frame_unref(input);
     462           0 :     av_frame_move_ref(input, output);
     463           0 :     av_frame_free(&output);
     464             : 
     465           0 :     return 0;
     466             : 
     467           0 : fail:
     468           0 :     av_frame_free(&output);
     469           0 :     return err;
     470             : }
     471             : 
     472           0 : int hwaccel_decode_init(AVCodecContext *avctx)
     473             : {
     474           0 :     InputStream *ist = avctx->opaque;
     475             : 
     476           0 :     ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;
     477             : 
     478           0 :     return 0;
     479             : }

Generated by: LCOV version 1.13