History

Merge commit 'd06aa24ba583ad08025da9e1b29afcd8218ff9b0'

* commit 'd06aa24ba583ad08025da9e1b29afcd8218ff9b0': hwcontext: Hardware frame mapping

Clément Bœsch committed 9 years ago

Commit 4cda23f2 parents 03f5e80 d06aa245 files · +365 −7Browse files

Unified · Split

5 files
  1. doc/APIchanges +4 −0
  2. libavutil/hwcontext.c +233 −6
  3. libavutil/hwcontext.h +87 −0
  4. libavutil/hwcontext_internal.h +40 −0
  5. libavutil/version.h +1 −1
doc/APIchanges+4−0
@@ -15,6 +15,10 @@ libavutil: 2015-08-28 · 14 unmodified lines
1515
1616 API changes, most recent first:
1717
18+2017-03-30 - xxxxxxx - lavu 55.53.100 / 55.27.0 - hwcontext.h
19+ Add av_hwframe_map() and associated AV_HWFRAME_MAP_* flags.
20+ Add av_hwframe_ctx_create_derived().
21+
1822 2017-03-xx - xxxxxxx - lavu 55.52.100 - avutil.h
1923 add av_fourcc_make_string() function and av_fourcc2str() macro to replace
2024 av_get_codec_tag_string() from lavc.
libavutil/hwcontext.c+233−6
@@ -157,14 +157,19 @@ static void hwframe_ctx_free(void *opaque, uint8_t *data) · 156 unmodified lines
157157 {
158158 AVHWFramesContext *ctx = (AVHWFramesContext*)data;
159159
160− if (ctx->internal->pool_internal)
161− av_buffer_pool_uninit(&ctx->internal->pool_internal);
160+ if (ctx->internal->source_frames) {
161+ av_buffer_unref(&ctx->internal->source_frames);
162162
163− if (ctx->internal->hw_type->frames_uninit)
164− ctx->internal->hw_type->frames_uninit(ctx);
163+ } else {
164+ if (ctx->internal->pool_internal)
165+ av_buffer_pool_uninit(&ctx->internal->pool_internal);
165166
166− if (ctx->free)
167− ctx->free(ctx);
167+ if (ctx->internal->hw_type->frames_uninit)
168+ ctx->internal->hw_type->frames_uninit(ctx);
169+
170+ if (ctx->free)
171+ ctx->free(ctx);
172+ }
168173
169174 av_buffer_unref(&ctx->device_ref);
170175
@@ -266,6 +271,11 @@ int av_hwframe_ctx_init(AVBufferRef *ref) · 95 unmodified lines
266271 const enum AVPixelFormat *pix_fmt;
267272 int ret;
268273
274+ if (ctx->internal->source_frames) {
275+ /* A derived frame context is already initialised. */
276+ return 0;
277+ }
278+
269279 /* validate the pixel format */
270280 for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) {
271281 if (*pix_fmt == ctx->format)
@@ -396,6 +406,35 @@ int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) · 124 unmodified lines
396406 AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
397407 int ret;
398408
409+ if (ctx->internal->source_frames) {
410+ // This is a derived frame context, so we allocate in the source
411+ // and map the frame immediately.
412+ AVFrame *src_frame;
413+
414+ src_frame = av_frame_alloc();
415+ if (!src_frame)
416+ return AVERROR(ENOMEM);
417+
418+ ret = av_hwframe_get_buffer(ctx->internal->source_frames,
419+ src_frame, 0);
420+ if (ret < 0)
421+ return ret;
422+
423+ ret = av_hwframe_map(frame, src_frame, 0);
424+ if (ret) {
425+ av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived "
426+ "frame context: %d.\n", ret);
427+ av_frame_free(&src_frame);
428+ return ret;
429+ }
430+
431+ // Free the source frame immediately - the mapped frame still
432+ // contains a reference to it.
433+ av_frame_free(&src_frame);
434+
435+ return 0;
436+ }
437+
399438 if (!ctx->internal->hw_type->frames_get_buffer)
400439 return AVERROR(ENOSYS);
401440
@@ -495,3 +534,191 @@ fail: · 93 unmodified lines
495534 *pdevice_ref = NULL;
496535 return ret;
497536 }
537+
538+static void ff_hwframe_unmap(void *opaque, uint8_t *data)
539+{
540+ HWMapDescriptor *hwmap = (HWMapDescriptor*)data;
541+ AVHWFramesContext *ctx = opaque;
542+
543+ if (hwmap->unmap)
544+ hwmap->unmap(ctx, hwmap);
545+
546+ av_frame_free(&hwmap->source);
547+
548+ av_buffer_unref(&hwmap->hw_frames_ctx);
549+
550+ av_free(hwmap);
551+}
552+
553+int ff_hwframe_map_create(AVBufferRef *hwframe_ref,
554+ AVFrame *dst, const AVFrame *src,
555+ void (*unmap)(AVHWFramesContext *ctx,
556+ HWMapDescriptor *hwmap),
557+ void *priv)
558+{
559+ AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
560+ HWMapDescriptor *hwmap;
561+ int ret;
562+
563+ hwmap = av_mallocz(sizeof(*hwmap));
564+ if (!hwmap) {
565+ ret = AVERROR(ENOMEM);
566+ goto fail;
567+ }
568+
569+ hwmap->source = av_frame_alloc();
570+ if (!hwmap->source) {
571+ ret = AVERROR(ENOMEM);
572+ goto fail;
573+ }
574+ ret = av_frame_ref(hwmap->source, src);
575+ if (ret < 0)
576+ goto fail;
577+
578+ hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref);
579+ if (!hwmap->hw_frames_ctx) {
580+ ret = AVERROR(ENOMEM);
581+ goto fail;
582+ }
583+
584+ hwmap->unmap = unmap;
585+ hwmap->priv = priv;
586+
587+ dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap),
588+ &ff_hwframe_unmap, ctx, 0);
589+ if (!dst->buf[0]) {
590+ ret = AVERROR(ENOMEM);
591+ goto fail;
592+ }
593+
594+ return 0;
595+
596+fail:
597+ if (hwmap) {
598+ av_buffer_unref(&hwmap->hw_frames_ctx);
599+ av_frame_free(&hwmap->source);
600+ }
601+ av_free(hwmap);
602+ return ret;
603+}
604+
605+int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
606+{
607+ AVHWFramesContext *src_frames, *dst_frames;
608+ HWMapDescriptor *hwmap;
609+ int ret;
610+
611+ if (src->hw_frames_ctx && dst->hw_frames_ctx) {
612+ src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data;
613+ dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data;
614+
615+ if ((src_frames == dst_frames &&
616+ src->format == dst_frames->sw_format &&
617+ dst->format == dst_frames->format) ||
618+ (src_frames->internal->source_frames &&
619+ src_frames->internal->source_frames->data ==
620+ (uint8_t*)dst_frames)) {
621+ // This is an unmap operation. We don't need to directly
622+ // do anything here other than fill in the original frame,
623+ // because the real unmap will be invoked when the last
624+ // reference to the mapped frame disappears.
625+ if (!src->buf[0]) {
626+ av_log(src_frames, AV_LOG_ERROR, "Invalid mapping "
627+ "found when attempting unmap.\n");
628+ return AVERROR(EINVAL);
629+ }
630+ hwmap = (HWMapDescriptor*)src->buf[0]->data;
631+ av_frame_unref(dst);
632+ return av_frame_ref(dst, hwmap->source);
633+ }
634+ }
635+
636+ if (src->hw_frames_ctx) {
637+ src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data;
638+
639+ if (src_frames->format == src->format &&
640+ src_frames->internal->hw_type->map_from) {
641+ ret = src_frames->internal->hw_type->map_from(src_frames,
642+ dst, src, flags);
643+ if (ret != AVERROR(ENOSYS))
644+ return ret;
645+ }
646+ }
647+
648+ if (dst->hw_frames_ctx) {
649+ dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data;
650+
651+ if (dst_frames->format == dst->format &&
652+ dst_frames->internal->hw_type->map_to) {
653+ ret = dst_frames->internal->hw_type->map_to(dst_frames,
654+ dst, src, flags);
655+ if (ret != AVERROR(ENOSYS))
656+ return ret;
657+ }
658+ }
659+
660+ return AVERROR(ENOSYS);
661+}
662+
663+int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx,
664+ enum AVPixelFormat format,
665+ AVBufferRef *derived_device_ctx,
666+ AVBufferRef *source_frame_ctx,
667+ int flags)
668+{
669+ AVBufferRef *dst_ref = NULL;
670+ AVHWFramesContext *dst = NULL;
671+ AVHWFramesContext *src = (AVHWFramesContext*)source_frame_ctx->data;
672+ int ret;
673+
674+ if (src->internal->source_frames) {
675+ AVHWFramesContext *src_src =
676+ (AVHWFramesContext*)src->internal->source_frames->data;
677+ AVHWDeviceContext *dst_dev =
678+ (AVHWDeviceContext*)derived_device_ctx->data;
679+
680+ if (src_src->device_ctx == dst_dev) {
681+ // This is actually an unmapping, so we just return a
682+ // reference to the source frame context.
683+ *derived_frame_ctx =
684+ av_buffer_ref(src->internal->source_frames);
685+ if (!*derived_frame_ctx) {
686+ ret = AVERROR(ENOMEM);
687+ goto fail;
688+ }
689+ return 0;
690+ }
691+ }
692+
693+ dst_ref = av_hwframe_ctx_alloc(derived_device_ctx);
694+ if (!dst_ref) {
695+ ret = AVERROR(ENOMEM);
696+ goto fail;
697+ }
698+
699+ dst = (AVHWFramesContext*)dst_ref->data;
700+
701+ dst->format = format;
702+ dst->sw_format = src->sw_format;
703+ dst->width = src->width;
704+ dst->height = src->height;
705+
706+ dst->internal->source_frames = av_buffer_ref(source_frame_ctx);
707+ if (!dst->internal->source_frames) {
708+ ret = AVERROR(ENOMEM);
709+ goto fail;
710+ }
711+
712+ ret = av_hwframe_ctx_init(dst_ref);
713+ if (ret)
714+ goto fail;
715+
716+ *derived_frame_ctx = dst_ref;
717+ return 0;
718+
719+fail:
720+ if (dst)
721+ av_buffer_unref(&dst->internal->source_frames);
722+ av_buffer_unref(&dst_ref);
723+ return ret;
724+}
libavutil/hwcontext.h+87−0
@@ -433,4 +433,91 @@ AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, · 432 unmodified lines
433433 */
434434 void av_hwframe_constraints_free(AVHWFramesConstraints **constraints);
435435
436+
437+/**
438+ * Flags to apply to frame mappings.
439+ */
440+enum {
441+ /**
442+ * The mapping must be readable.
443+ */
444+ AV_HWFRAME_MAP_READ = 1 << 0,
445+ /**
446+ * The mapping must be writeable.
447+ */
448+ AV_HWFRAME_MAP_WRITE = 1 << 1,
449+ /**
450+ * The mapped frame will be overwritten completely in subsequent
451+ * operations, so the current frame data need not be loaded. Any values
452+ * which are not overwritten are unspecified.
453+ */
454+ AV_HWFRAME_MAP_OVERWRITE = 1 << 2,
455+ /**
456+ * The mapping must be direct. That is, there must not be any copying in
457+ * the map or unmap steps. Note that performance of direct mappings may
458+ * be much lower than normal memory.
459+ */
460+ AV_HWFRAME_MAP_DIRECT = 1 << 3,
461+};
462+
463+/**
464+ * Map a hardware frame.
465+ *
466+ * This has a number of different possible effects, depending on the format
467+ * and origin of the src and dst frames. On input, src should be a usable
468+ * frame with valid buffers and dst should be blank (typically as just created
469+ * by av_frame_alloc()). src should have an associated hwframe context, and
470+ * dst may optionally have a format and associated hwframe context.
471+ *
472+ * If src was created by mapping a frame from the hwframe context of dst,
473+ * then this function undoes the mapping - dst is replaced by a reference to
474+ * the frame that src was originally mapped from.
475+ *
476+ * If both src and dst have an associated hwframe context, then this function
477+ * attempts to map the src frame from its hardware context to that of dst and
478+ * then fill dst with appropriate data to be usable there. This will only be
479+ * possible if the hwframe contexts and associated devices are compatible -
480+ * given compatible devices, av_hwframe_ctx_create_derived() can be used to
481+ * create a hwframe context for dst in which mapping should be possible.
482+ *
483+ * If src has a hwframe context but dst does not, then the src frame is
484+ * mapped to normal memory and should thereafter be usable as a normal frame.
485+ * If the format is set on dst, then the mapping will attempt to create dst
486+ * with that format and fail if it is not possible. If format is unset (is
487+ * AV_PIX_FMT_NONE) then dst will be mapped with whatever the most appropriate
488+ * format to use is (probably the sw_format of the src hwframe context).
489+ *
490+ * A return value of AVERROR(ENOSYS) indicates that the mapping is not
491+ * possible with the given arguments and hwframe setup, while other return
492+ * values indicate that it failed somehow.
493+ *
494+ * @param dst Destination frame, to contain the mapping.
495+ * @param src Source frame, to be mapped.
496+ * @param flags Some combination of AV_HWFRAME_MAP_* flags.
497+ * @return Zero on success, negative AVERROR code on failure.
498+ */
499+int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags);
500+
501+
502+/**
503+ * Create and initialise an AVHWFramesContext as a mapping of another existing
504+ * AVHWFramesContext on a different device.
505+ *
506+ * av_hwframe_ctx_init() should not be called after this.
507+ *
508+ * @param derived_frame_ctx On success, a reference to the newly created
509+ * AVHWFramesContext.
510+ * @param derived_device_ctx A reference to the device to create the new
511+ * AVHWFramesContext on.
512+ * @param source_frame_ctx A reference to an existing AVHWFramesContext
513+ * which will be mapped to the derived context.
514+ * @param flags Currently unused; should be set to zero.
515+ * @return Zero on success, negative AVERROR code on failure.
516+ */
517+int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx,
518+ enum AVPixelFormat format,
519+ AVBufferRef *derived_device_ctx,
520+ AVBufferRef *source_frame_ctx,
521+ int flags);
522+
436523 #endif /* AVUTIL_HWCONTEXT_H */
libavutil/hwcontext_internal.h+40−0
@@ -85,6 +85,11 @@ typedef struct HWContextType { · 84 unmodified lines
8585 const AVFrame *src);
8686 int (*transfer_data_from)(AVHWFramesContext *ctx, AVFrame *dst,
8787 const AVFrame *src);
88+
89+ int (*map_to)(AVHWFramesContext *ctx, AVFrame *dst,
90+ const AVFrame *src, int flags);
91+ int (*map_from)(AVHWFramesContext *ctx, AVFrame *dst,
92+ const AVFrame *src, int flags);
8893 } HWContextType;
8994
9095 struct AVHWDeviceInternal {
@@ -97,8 +102,43 @@ struct AVHWFramesInternal { · 6 unmodified lines
97102 void *priv;
98103
99104 AVBufferPool *pool_internal;
105+
106+ /**
107+ * For a derived context, a reference to the original frames
108+ * context it was derived from.
109+ */
110+ AVBufferRef *source_frames;
100111 };
101112
113+typedef struct HWMapDescriptor {
114+ /**
115+ * A reference to the original source of the mapping.
116+ */
117+ AVFrame *source;
118+ /**
119+ * A reference to the hardware frames context in which this
120+ * mapping was made. May be the same as source->hw_frames_ctx,
121+ * but need not be.
122+ */
123+ AVBufferRef *hw_frames_ctx;
124+ /**
125+ * Unmap function.
126+ */
127+ void (*unmap)(AVHWFramesContext *ctx,
128+ struct HWMapDescriptor *hwmap);
129+ /**
130+ * Hardware-specific private data associated with the mapping.
131+ */
132+ void *priv;
133+} HWMapDescriptor;
134+
135+int ff_hwframe_map_create(AVBufferRef *hwframe_ref,
136+ AVFrame *dst, const AVFrame *src,
137+ void (*unmap)(AVHWFramesContext *ctx,
138+ HWMapDescriptor *hwmap),
139+ void *priv);
140+
141+
102142 extern const HWContextType ff_hwcontext_type_cuda;
103143 extern const HWContextType ff_hwcontext_type_dxva2;
104144 extern const HWContextType ff_hwcontext_type_qsv;
libavutil/version.h+1−1
@@ -79,7 +79,7 @@ · 78 unmodified lines
7979 */
8080
8181 #define LIBAVUTIL_VERSION_MAJOR 55
82−#define LIBAVUTIL_VERSION_MINOR 52
82+#define LIBAVUTIL_VERSION_MINOR 53
8383 #define LIBAVUTIL_VERSION_MICRO 100
8484
8585 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t