123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- /*
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #include <string.h>
- #include "libavutil/avstring.h"
- #include "libavutil/pixdesc.h"
- #include "libavfilter/buffersink.h"
- #include "ffmpeg.h"
- static int nb_hw_devices;
- static HWDevice **hw_devices;
- HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
- {
- HWDevice *found = NULL;
- int i;
- for (i = 0; i < nb_hw_devices; i++) {
- if (hw_devices[i]->type == type) {
- if (found)
- return NULL;
- found = hw_devices[i];
- }
- }
- return found;
- }
- HWDevice *hw_device_get_by_name(const char *name)
- {
- int i;
- for (i = 0; i < nb_hw_devices; i++) {
- if (!strcmp(hw_devices[i]->name, name))
- return hw_devices[i];
- }
- return NULL;
- }
- static HWDevice *hw_device_add(void)
- {
- int err;
- err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
- sizeof(*hw_devices));
- if (err) {
- nb_hw_devices = 0;
- return NULL;
- }
- hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
- if (!hw_devices[nb_hw_devices])
- return NULL;
- return hw_devices[nb_hw_devices++];
- }
- static char *hw_device_default_name(enum AVHWDeviceType type)
- {
- // Make an automatic name of the form "type%d". We arbitrarily
- // limit at 1000 anonymous devices of the same type - there is
- // probably something else very wrong if you get to this limit.
- const char *type_name = av_hwdevice_get_type_name(type);
- char *name;
- size_t index_pos;
- int index, index_limit = 1000;
- index_pos = strlen(type_name);
- name = av_malloc(index_pos + 4);
- if (!name)
- return NULL;
- for (index = 0; index < index_limit; index++) {
- snprintf(name, index_pos + 4, "%s%d", type_name, index);
- if (!hw_device_get_by_name(name))
- break;
- }
- if (index >= index_limit) {
- av_freep(&name);
- return NULL;
- }
- return name;
- }
- int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
- {
- // "type=name"
- // "type=name,key=value,key2=value2"
- // "type=name:device,key=value,key2=value2"
- // "type:device,key=value,key2=value2"
- // -> av_hwdevice_ctx_create()
- // "type=name@name"
- // "type@name"
- // -> av_hwdevice_ctx_create_derived()
- AVDictionary *options = NULL;
- const char *type_name = NULL, *name = NULL, *device = NULL;
- enum AVHWDeviceType type;
- HWDevice *dev, *src;
- AVBufferRef *device_ref = NULL;
- int err;
- const char *errmsg, *p, *q;
- size_t k;
- k = strcspn(arg, ":=@");
- p = arg + k;
- type_name = av_strndup(arg, k);
- if (!type_name) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- type = av_hwdevice_find_type_by_name(type_name);
- if (type == AV_HWDEVICE_TYPE_NONE) {
- errmsg = "unknown device type";
- goto invalid;
- }
- if (*p == '=') {
- k = strcspn(p + 1, ":@,");
- name = av_strndup(p + 1, k);
- if (!name) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- if (hw_device_get_by_name(name)) {
- errmsg = "named device already exists";
- goto invalid;
- }
- p += 1 + k;
- } else {
- name = hw_device_default_name(type);
- if (!name) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- }
- if (!*p) {
- // New device with no parameters.
- err = av_hwdevice_ctx_create(&device_ref, type,
- NULL, NULL, 0);
- if (err < 0)
- goto fail;
- } else if (*p == ':') {
- // New device with some parameters.
- ++p;
- q = strchr(p, ',');
- if (q) {
- if (q - p > 0) {
- device = av_strndup(p, q - p);
- if (!device) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- }
- err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
- if (err < 0) {
- errmsg = "failed to parse options";
- goto invalid;
- }
- }
- err = av_hwdevice_ctx_create(&device_ref, type,
- q ? device : p[0] ? p : NULL,
- options, 0);
- if (err < 0)
- goto fail;
- } else if (*p == '@') {
- // Derive from existing device.
- src = hw_device_get_by_name(p + 1);
- if (!src) {
- errmsg = "invalid source device name";
- goto invalid;
- }
- err = av_hwdevice_ctx_create_derived(&device_ref, type,
- src->device_ref, 0);
- if (err < 0)
- goto fail;
- } else if (*p == ',') {
- err = av_dict_parse_string(&options, p + 1, "=", ",", 0);
- if (err < 0) {
- errmsg = "failed to parse options";
- goto invalid;
- }
- err = av_hwdevice_ctx_create(&device_ref, type,
- NULL, options, 0);
- if (err < 0)
- goto fail;
- } else {
- errmsg = "parse error";
- goto invalid;
- }
- dev = hw_device_add();
- if (!dev) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- dev->name = name;
- dev->type = type;
- dev->device_ref = device_ref;
- if (dev_out)
- *dev_out = dev;
- name = NULL;
- err = 0;
- done:
- av_freep(&type_name);
- av_freep(&name);
- av_freep(&device);
- av_dict_free(&options);
- return err;
- invalid:
- av_log(NULL, AV_LOG_ERROR,
- "Invalid device specification \"%s\": %s\n", arg, errmsg);
- err = AVERROR(EINVAL);
- goto done;
- fail:
- av_log(NULL, AV_LOG_ERROR,
- "Device creation failed: %d.\n", err);
- av_buffer_unref(&device_ref);
- goto done;
- }
- int hw_device_init_from_type(enum AVHWDeviceType type,
- const char *device,
- HWDevice **dev_out)
- {
- AVBufferRef *device_ref = NULL;
- HWDevice *dev;
- char *name;
- int err;
- name = hw_device_default_name(type);
- if (!name) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
- if (err < 0) {
- av_log(NULL, AV_LOG_ERROR,
- "Device creation failed: %d.\n", err);
- goto fail;
- }
- dev = hw_device_add();
- if (!dev) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- dev->name = name;
- dev->type = type;
- dev->device_ref = device_ref;
- if (dev_out)
- *dev_out = dev;
- return 0;
- fail:
- av_freep(&name);
- av_buffer_unref(&device_ref);
- return err;
- }
- void hw_device_free_all(void)
- {
- int i;
- for (i = 0; i < nb_hw_devices; i++) {
- av_freep(&hw_devices[i]->name);
- av_buffer_unref(&hw_devices[i]->device_ref);
- av_freep(&hw_devices[i]);
- }
- av_freep(&hw_devices);
- nb_hw_devices = 0;
- }
- int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
- {
- InputStream *ist = avctx->opaque;
- AVFrame *output = NULL;
- enum AVPixelFormat output_format = ist->hwaccel_output_format;
- int err;
- if (input->format == output_format) {
- // Nothing to do.
- return 0;
- }
- output = av_frame_alloc();
- if (!output)
- return AVERROR(ENOMEM);
- output->format = output_format;
- err = av_hwframe_transfer_data(output, input, 0);
- if (err < 0) {
- av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
- "output frame: %d.\n", err);
- goto fail;
- }
- err = av_frame_copy_props(output, input);
- if (err < 0) {
- av_frame_unref(output);
- goto fail;
- }
- av_frame_unref(input);
- av_frame_move_ref(input, output);
- av_frame_free(&output);
- return 0;
- fail:
- av_frame_free(&output);
- return err;
- }
- AVBufferRef *hw_device_for_filter(void)
- {
- // Pick the last hardware device if the user doesn't pick the device for
- // filters explicitly with the filter_hw_device option.
- if (filter_hw_device)
- return filter_hw_device->device_ref;
- else if (nb_hw_devices > 0) {
- HWDevice *dev = hw_devices[nb_hw_devices - 1];
- if (nb_hw_devices > 1)
- av_log(NULL, AV_LOG_WARNING, "There are %d hardware devices. device "
- "%s of type %s is picked for filters by default. Set hardware "
- "device explicitly with the filter_hw_device option if device "
- "%s is not usable for filters.\n",
- nb_hw_devices, dev->name,
- av_hwdevice_get_type_name(dev->type), dev->name);
- return dev->device_ref;
- }
- return NULL;
- }
|