Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
FFmpeg
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
libremedia
Tethys
FFmpeg
Commits
02c27619
Commit
02c27619
authored
8 years ago
by
Anton Khirnov
Browse files
Options
Downloads
Patches
Plain Diff
avconv_qsv: use the device creation API
parent
232399e3
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
avconv_qsv.c
+38
-209
38 additions, 209 deletions
avconv_qsv.c
with
38 additions
and
209 deletions
avconv_qsv.c
+
38
−
209
View file @
02c27619
...
...
@@ -20,248 +20,77 @@
#include
<stdlib.h>
#include
"libavutil/dict.h"
#include
"libavutil/hwcontext.h"
#include
"libavutil/hwcontext_qsv.h"
#include
"libavutil/mem.h"
#include
"libavutil/opt.h"
#include
"libavcodec/qsv.h"
#include
"avconv.h"
typedef
struct
QSVContext
{
OutputStream
*
ost
;
mfxSession
session
;
mfxExtOpaqueSurfaceAlloc
opaque_alloc
;
AVBufferRef
*
opaque_surfaces_buf
;
uint8_t
*
surface_used
;
mfxFrameSurface1
**
surface_ptrs
;
int
nb_surfaces
;
mfxExtBuffer
*
ext_buffers
[
1
];
}
QSVContext
;
static
void
buffer_release
(
void
*
opaque
,
uint8_t
*
data
)
{
*
(
uint8_t
*
)
opaque
=
0
;
}
static
int
qsv_get_buffer
(
AVCodecContext
*
s
,
AVFrame
*
frame
,
int
flags
)
{
InputStream
*
ist
=
s
->
opaque
;
QSVContext
*
qsv
=
ist
->
hwaccel_ctx
;
int
i
;
for
(
i
=
0
;
i
<
qsv
->
nb_surfaces
;
i
++
)
{
if
(
qsv
->
surface_used
[
i
])
continue
;
frame
->
buf
[
0
]
=
av_buffer_create
((
uint8_t
*
)
qsv
->
surface_ptrs
[
i
],
sizeof
(
*
qsv
->
surface_ptrs
[
i
]),
buffer_release
,
&
qsv
->
surface_used
[
i
],
0
);
if
(
!
frame
->
buf
[
0
])
return
AVERROR
(
ENOMEM
);
frame
->
data
[
3
]
=
(
uint8_t
*
)
qsv
->
surface_ptrs
[
i
];
qsv
->
surface_used
[
i
]
=
1
;
return
0
;
}
return
AVERROR
(
ENOMEM
);
}
static
int
init_opaque_surf
(
QSVContext
*
qsv
)
{
AVQSVContext
*
hwctx_enc
=
qsv
->
ost
->
enc_ctx
->
hwaccel_context
;
mfxFrameSurface1
*
surfaces
;
int
i
;
qsv
->
nb_surfaces
=
hwctx_enc
->
nb_opaque_surfaces
;
qsv
->
opaque_surfaces_buf
=
av_buffer_ref
(
hwctx_enc
->
opaque_surfaces
);
qsv
->
surface_ptrs
=
av_mallocz_array
(
qsv
->
nb_surfaces
,
sizeof
(
*
qsv
->
surface_ptrs
));
qsv
->
surface_used
=
av_mallocz_array
(
qsv
->
nb_surfaces
,
sizeof
(
*
qsv
->
surface_used
));
if
(
!
qsv
->
opaque_surfaces_buf
||
!
qsv
->
surface_ptrs
||
!
qsv
->
surface_used
)
return
AVERROR
(
ENOMEM
);
surfaces
=
(
mfxFrameSurface1
*
)
qsv
->
opaque_surfaces_buf
->
data
;
for
(
i
=
0
;
i
<
qsv
->
nb_surfaces
;
i
++
)
qsv
->
surface_ptrs
[
i
]
=
surfaces
+
i
;
qsv
->
opaque_alloc
.
Out
.
Surfaces
=
qsv
->
surface_ptrs
;
qsv
->
opaque_alloc
.
Out
.
NumSurface
=
qsv
->
nb_surfaces
;
qsv
->
opaque_alloc
.
Out
.
Type
=
hwctx_enc
->
opaque_alloc_type
;
qsv
->
opaque_alloc
.
Header
.
BufferId
=
MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION
;
qsv
->
opaque_alloc
.
Header
.
BufferSz
=
sizeof
(
qsv
->
opaque_alloc
);
qsv
->
ext_buffers
[
0
]
=
(
mfxExtBuffer
*
)
&
qsv
->
opaque_alloc
;
return
0
;
return
av_hwframe_get_buffer
(
ist
->
hw_frames_ctx
,
frame
,
0
);
}
static
void
qsv_uninit
(
AVCodecContext
*
s
)
{
InputStream
*
ist
=
s
->
opaque
;
QSVContext
*
qsv
=
ist
->
hwaccel_ctx
;
av_freep
(
&
qsv
->
ost
->
enc_ctx
->
hwaccel_context
);
av_freep
(
&
s
->
hwaccel_context
);
av_buffer_unref
(
&
qsv
->
opaque_surfaces_buf
);
av_freep
(
&
qsv
->
surface_used
);
av_freep
(
&
qsv
->
surface_ptrs
);
av_freep
(
&
qsv
);
av_buffer_unref
(
&
ist
->
hw_frames_ctx
);
}
int
qsv_
init
(
AVCodecContext
*
s
)
static
int
qsv_
device_init
(
InputStream
*
ist
)
{
InputStream
*
ist
=
s
->
opaque
;
QSVContext
*
qsv
=
ist
->
hwaccel_ctx
;
AVQSVContext
*
hwctx_dec
;
int
ret
;
int
err
;
if
(
!
qsv
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"QSV transcoding is not initialized. "
"-hwaccel qsv should only be used for one-to-one QSV transcoding "
"with no filters.
\n
"
);
return
AVERROR_BUG
;
err
=
av_hwdevice_ctx_create
(
&
hw_device_ctx
,
AV_HWDEVICE_TYPE_QSV
,
ist
->
hwaccel_device
,
NULL
,
0
);
if
(
err
<
0
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"Error creating a QSV device
\n
"
);
return
err
;
}
ret
=
init_opaque_surf
(
qsv
);
if
(
ret
<
0
)
return
ret
;
hwctx_dec
=
av_qsv_alloc_context
();
if
(
!
hwctx_dec
)
return
AVERROR
(
ENOMEM
);
hwctx_dec
->
session
=
qsv
->
session
;
hwctx_dec
->
iopattern
=
MFX_IOPATTERN_OUT_OPAQUE_MEMORY
;
hwctx_dec
->
ext_buffers
=
qsv
->
ext_buffers
;
hwctx_dec
->
nb_ext_buffers
=
FF_ARRAY_ELEMS
(
qsv
->
ext_buffers
);
av_freep
(
&
s
->
hwaccel_context
);
s
->
hwaccel_context
=
hwctx_dec
;
ist
->
hwaccel_get_buffer
=
qsv_get_buffer
;
ist
->
hwaccel_uninit
=
qsv_uninit
;
return
0
;
}
static
mfxIMPL
choose_implementation
(
const
InputStream
*
ist
)
int
qsv_init
(
AVCodecContext
*
s
)
{
static
const
struct
{
const
char
*
name
;
mfxIMPL
impl
;
}
impl_map
[]
=
{
{
"auto"
,
MFX_IMPL_AUTO
},
{
"sw"
,
MFX_IMPL_SOFTWARE
},
{
"hw"
,
MFX_IMPL_HARDWARE
},
{
"auto_any"
,
MFX_IMPL_AUTO_ANY
},
{
"hw_any"
,
MFX_IMPL_HARDWARE_ANY
},
{
"hw2"
,
MFX_IMPL_HARDWARE2
},
{
"hw3"
,
MFX_IMPL_HARDWARE3
},
{
"hw4"
,
MFX_IMPL_HARDWARE4
},
};
mfxIMPL
impl
=
MFX_IMPL_AUTO_ANY
;
int
i
;
InputStream
*
ist
=
s
->
opaque
;
AVHWFramesContext
*
frames_ctx
;
AVQSVFramesContext
*
frames_hwctx
;
int
ret
;
if
(
ist
->
hwaccel_device
)
{
for
(
i
=
0
;
i
<
FF_ARRAY_ELEMS
(
impl_map
);
i
++
)
if
(
!
strcmp
(
ist
->
hwaccel_device
,
impl_map
[
i
].
name
))
{
impl
=
impl_map
[
i
].
impl
;
break
;
}
if
(
i
==
FF_ARRAY_ELEMS
(
impl_map
))
impl
=
strtol
(
ist
->
hwaccel_device
,
NULL
,
0
);
if
(
!
hw_device_ctx
)
{
ret
=
qsv_device_init
(
ist
);
if
(
ret
<
0
)
return
ret
;
}
return
impl
;
}
int
qsv_transcode_init
(
OutputStream
*
ost
)
{
InputStream
*
ist
;
const
enum
AVPixelFormat
*
pix_fmt
;
AVDictionaryEntry
*
e
;
const
AVOption
*
opt
;
int
flags
=
0
;
int
err
,
i
;
QSVContext
*
qsv
=
NULL
;
AVQSVContext
*
hwctx
=
NULL
;
mfxIMPL
impl
;
mfxVersion
ver
=
{
{
3
,
1
}
};
/* check if the encoder supports QSV */
if
(
!
ost
->
enc
->
pix_fmts
)
return
0
;
for
(
pix_fmt
=
ost
->
enc
->
pix_fmts
;
*
pix_fmt
!=
AV_PIX_FMT_NONE
;
pix_fmt
++
)
if
(
*
pix_fmt
==
AV_PIX_FMT_QSV
)
break
;
if
(
*
pix_fmt
==
AV_PIX_FMT_NONE
)
return
0
;
if
(
strcmp
(
ost
->
avfilter
,
"null"
)
||
ost
->
source_index
<
0
)
return
0
;
/* check if the decoder supports QSV and the output only goes to this stream */
ist
=
input_streams
[
ost
->
source_index
];
if
(
ist
->
nb_filters
||
ist
->
hwaccel_id
!=
HWACCEL_QSV
||
!
ist
->
dec
||
!
ist
->
dec
->
pix_fmts
)
return
0
;
for
(
pix_fmt
=
ist
->
dec
->
pix_fmts
;
*
pix_fmt
!=
AV_PIX_FMT_NONE
;
pix_fmt
++
)
if
(
*
pix_fmt
==
AV_PIX_FMT_QSV
)
break
;
if
(
*
pix_fmt
==
AV_PIX_FMT_NONE
)
return
0
;
for
(
i
=
0
;
i
<
nb_output_streams
;
i
++
)
if
(
output_streams
[
i
]
!=
ost
&&
output_streams
[
i
]
->
source_index
==
ost
->
source_index
)
return
0
;
av_log
(
NULL
,
AV_LOG_VERBOSE
,
"Setting up QSV transcoding
\n
"
);
av_buffer_unref
(
&
ist
->
hw_frames_ctx
);
ist
->
hw_frames_ctx
=
av_hwframe_ctx_alloc
(
hw_device_ctx
);
if
(
!
ist
->
hw_frames_ctx
)
return
AVERROR
(
ENOMEM
);
qsv
=
av_mallocz
(
sizeof
(
*
qsv
));
hwctx
=
av_qsv_alloc_context
();
if
(
!
qsv
||
!
hwctx
)
goto
fail
;
frames_ctx
=
(
AVHWFramesContext
*
)
ist
->
hw_frames_ctx
->
data
;
frames_hwctx
=
frames_ctx
->
hwctx
;
impl
=
choose_implementation
(
ist
);
frames_ctx
->
width
=
s
->
coded_width
;
frames_ctx
->
height
=
s
->
coded_height
;
frames_ctx
->
format
=
AV_PIX_FMT_QSV
;
frames_ctx
->
sw_format
=
AV_PIX_FMT_NV12
;
frames_ctx
->
initial_pool_size
=
32
;
frames_hwctx
->
frame_type
=
MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET
;
err
=
MFXInit
(
impl
,
&
ver
,
&
qsv
->
session
);
if
(
err
!=
MFX_ERR_NONE
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"Error initializing a
n MFX session: %d
\n
"
,
err
);
goto
fail
;
ret
=
av_hwframe_ctx_init
(
ist
->
hw_frames_ctx
);
if
(
ret
<
0
)
{
av_log
(
NULL
,
AV_LOG_ERROR
,
"Error initializing a
QSV frame pool
\n
"
);
return
ret
;
}
e
=
av_dict_get
(
ost
->
encoder_opts
,
"flags"
,
NULL
,
0
);
opt
=
av_opt_find
(
ost
->
enc_ctx
,
"flags"
,
NULL
,
0
,
0
);
if
(
e
&&
opt
)
av_opt_eval_flags
(
ost
->
enc_ctx
,
opt
,
e
->
value
,
&
flags
);
qsv
->
ost
=
ost
;
hwctx
->
session
=
qsv
->
session
;
hwctx
->
iopattern
=
MFX_IOPATTERN_IN_OPAQUE_MEMORY
;
hwctx
->
opaque_alloc
=
1
;
hwctx
->
nb_opaque_surfaces
=
16
;
ost
->
hwaccel_ctx
=
qsv
;
ost
->
enc_ctx
->
hwaccel_context
=
hwctx
;
ost
->
enc_ctx
->
pix_fmt
=
AV_PIX_FMT_QSV
;
ist
->
hwaccel_ctx
=
qsv
;
ist
->
dec_ctx
->
pix_fmt
=
AV_PIX_FMT_QSV
;
ist
->
hwaccel_get_buffer
=
qsv_get_buffer
;
ist
->
hwaccel_uninit
=
qsv_uninit
;
return
0
;
fail:
av_freep
(
&
hwctx
);
av_freep
(
&
qsv
);
return
AVERROR_UNKNOWN
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment