Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
ftl
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
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
Nicolas Pope
ftl
Commits
0319d141
Commit
0319d141
authored
5 years ago
by
Sebastian
Browse files
Options
Downloads
Patches
Plain Diff
fix colors (channel order)
parent
a48b5c69
No related branches found
No related tags found
2 merge requests
!155
Feature/python
,
!141
Python module for reading .ftl files
Pipeline
#15872
passed
5 years ago
Stage: all
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
python/ftl/ftlstream.py
+113
-1
113 additions, 1 deletion
python/ftl/ftlstream.py
python/ftl/libde265.py
+81
-66
81 additions, 66 deletions
python/ftl/libde265.py
with
194 additions
and
67 deletions
python/ftl/ftlstream.py
+
113
−
1
View file @
0319d141
import
msgpack
import
numpy
as
np
from
enum
import
IntEnum
from
collections
import
namedtuple
from
.
libde265
import
Decoder
try
:
import
cv2
as
cv
def
ycbcr2rgb
(
img
):
raise
NotImplementedError
(
"
TODO
"
)
except
ImportError
:
import
skimage.color
def
ycbcr2rgb
(
img
):
res
=
skimage
.
color
.
ycbcr2rgb
(
img
.
astype
(
np
.
float
))
# clip
res
[
res
>
1.0
]
=
1.0
res
[
res
<
0.0
]
=
0.0
# skimage ycbcr2rgb() returns dtype float64, convert to uint8
return
(
res
*
255
).
astype
(
np
.
uint8
)
# FTL definitions
_packet
=
namedtuple
(
"
Packet
"
,
[
"
codec
"
,
"
definition
"
,
"
block_total
"
,
"
block_number
"
,
"
flags
"
,
"
data
"
])
_stream_packet
=
namedtuple
(
"
StreamPacket
"
,
[
"
timestamp
"
,
"
streamID
"
,
"
chanel_count
"
,
"
channel
"
])
...
...
@@ -17,6 +40,88 @@ _definition_t = {
8
:
()
}
class
NALType
(
IntEnum
):
CODED_SLICE_TRAIL_N
=
0
CODED_SLICE_TRAIL_R
=
1
CODED_SLICE_TSA_N
=
2
CODED_SLICE_TSA_R
=
3
CODED_SLICE_STSA_N
=
4
CODED_SLICE_STSA_R
=
5
CODED_SLICE_RADL_N
=
6
CODED_SLICE_RADL_R
=
7
CODED_SLICE_RASL_N
=
8
CODED_SLICE_RASL_R
=
9
RESERVED_VCL_N10
=
10
RESERVED_VCL_R11
=
11
RESERVED_VCL_N12
=
12
RESERVED_VCL_R13
=
13
RESERVED_VCL_N14
=
14
RESERVED_VCL_R15
=
15
CODED_SLICE_BLA_W_LP
=
16
CODED_SLICE_BLA_W_RADL
=
17
CODED_SLICE_BLA_N_LP
=
18
CODED_SLICE_IDR_W_RADL
=
19
CODED_SLICE_IDR_N_LP
=
20
CODED_SLICE_CRA
=
21
RESERVED_IRAP_VCL22
=
22
RESERVED_IRAP_VCL23
=
23
RESERVED_VCL24
=
24
RESERVED_VCL25
=
25
RESERVED_VCL26
=
26
RESERVED_VCL27
=
27
RESERVED_VCL28
=
28
RESERVED_VCL29
=
29
RESERVED_VCL30
=
30
RESERVED_VCL31
=
31
VPS
=
32
SPS
=
33
PPS
=
34
ACCESS_UNIT_DELIMITER
=
35
EOS
=
36
EOB
=
37
FILLER_DATA
=
38
PREFIX_SEI
=
39
SUFFIX_SEI
=
40
RESERVED_NVCL41
=
41
RESERVED_NVCL42
=
42
RESERVED_NVCL43
=
43
RESERVED_NVCL44
=
44
RESERVED_NVCL45
=
45
RESERVED_NVCL46
=
46
RESERVED_NVCL47
=
47
UNSPECIFIED_48
=
48
UNSPECIFIED_49
=
49
UNSPECIFIED_50
=
50
UNSPECIFIED_51
=
51
UNSPECIFIED_52
=
52
UNSPECIFIED_53
=
53
UNSPECIFIED_54
=
54
UNSPECIFIED_55
=
55
UNSPECIFIED_56
=
56
UNSPECIFIED_57
=
57
UNSPECIFIED_58
=
58
UNSPECIFIED_59
=
59
UNSPECIFIED_60
=
60
UNSPECIFIED_61
=
61
UNSPECIFIED_62
=
62
UNSPECIFIED_63
=
63
INVALID
=
64
def
get_NAL_type
(
data
):
if
not
isinstance
(
data
,
bytes
):
raise
ValueError
(
"
expected bytes
"
)
return
NALType
((
data
[
4
]
>>
1
)
&
0x3f
)
class
FTLStream
:
def
__init__
(
self
,
file
):
self
.
_file
=
open
(
file
,
"
br
"
)
...
...
@@ -60,12 +165,18 @@ class FTLStream:
self
.
_decoders
[
k
]
=
Decoder
(
_definition_t
[
p
.
definition
])
decoder
=
self
.
_decoders
[
k
]
decoder
.
push_data
(
p
.
data
)
decoder
.
decode
()
img
=
decoder
.
get_next_picture
()
if
img
is
not
None
:
self
.
_frames
[
k
]
=
img
self
.
_frames
[
k
]
=
ycbcr2rgb
(
img
[:,:,(
0
,
2
,
1
)])
# note: channels BGR
def
_flush_decoders
(
self
):
for
decoder
in
self
.
_decoders
.
values
():
decoder
.
flush_data
()
def
read
(
self
):
'''
...
...
@@ -99,6 +210,7 @@ class FTLStream:
raise
ValueError
(
"
unkowno codec %i
"
%
p
.
codec
)
except
Exception
as
e
:
# TODO: Multiple exceptions possible. Re-design read()?
ex
=
e
try
:
...
...
This diff is collapsed.
Click to expand it.
python/ftl/libde265.py
+
81
−
66
View file @
0319d141
...
...
@@ -4,62 +4,78 @@ Python wrapper for libde265. Only decoding is (partly) implemented.
Requirements:
* libde265 library (libde265.so.0)
* numpy
*
skimage (rescaling)
*
opencv or skimage
'''
try
:
import
cv2
as
cv
# TODO: test
def
resize
(
img
,
size
):
return
cv
.
resize
(
img
,
dsize
=
reversed
(
size
),
interpolation
=
cv
.
INTER_CUBIC
)
except
ImportError
:
from
skimage.transform
import
resize
as
resize_skimage
def
resize
(
img
,
size
):
# skimage resize() return dtype float64, convert back to uint8
# order: 0 nn, 1 bilinear, 3 bicubic
return
(
resize_skimage
(
img
,
size
,
order
=
3
,
mode
=
"
constant
"
,
cval
=
0
)
*
255
).
astype
(
np
.
uint8
)
import
ctypes
from
enum
import
IntEnum
import
numpy
as
np
from
skimage.transform
import
rescale
# error codes copied from header (de265.h)
DE265_OK
=
0
DE265_ERROR_NO_SUCH_FILE
=
1
DE265_ERROR_COEFFICIENT_OUT_OF_IMAGE_BOUNDS
=
4
DE265_ERROR_CHECKSUM_MISMATCH
=
5
DE265_ERROR_CTB_OUTSIDE_IMAGE_AREA
=
6
DE265_ERROR_OUT_OF_MEMORY
=
7
DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE
=
8
DE265_ERROR_IMAGE_BUFFER_FULL
=
9
DE265_ERROR_CANNOT_START_THREADPOOL
=
10
DE265_ERROR_LIBRARY_INITIALIZATION_FAILED
=
11
DE265_ERROR_LIBRARY_NOT_INITIALIZED
=
12
DE265_ERROR_WAITING_FOR_INPUT_DATA
=
13
DE265_ERROR_CANNOT_PROCESS_SEI
=
14
DE265_ERROR_PARAMETER_PARSING
=
15
DE265_ERROR_NO_INITIAL_SLICE_HEADER
=
16
DE265_ERROR_PREMATURE_END_OF_SLICE
=
17
DE265_ERROR_UNSPECIFIED_DECODING_ERROR
=
18
DE265_ERROR_NOT_IMPLEMENTED_YET
=
502
DE265_WARNING_NO_WPP_CANNOT_USE_MULTITHREADING
=
1000
DE265_WARNING_WARNING_BUFFER_FULL
=
1001
DE265_WARNING_PREMATURE_END_OF_SLICE_SEGMENT
=
1002
DE265_WARNING_INCORRECT_ENTRY_POINT_OFFSET
=
1003
DE265_WARNING_CTB_OUTSIDE_IMAGE_AREA
=
1004
DE265_WARNING_SPS_HEADER_INVALID
=
1005
DE265_WARNING_PPS_HEADER_INVALID
=
1006
DE265_WARNING_SLICEHEADER_INVALID
=
1007
DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING
=
1008
DE265_WARNING_NONEXISTING_PPS_REFERENCED
=
1009
DE265_WARNING_NONEXISTING_SPS_REFERENCED
=
1010
DE265_WARNING_BOTH_PREDFLAGS_ZERO
=
1011
DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED
=
1012
DE265_WARNING_NUMMVP_NOT_EQUAL_TO_NUMMVQ
=
1013
DE265_WARNING_NUMBER_OF_SHORT_TERM_REF_PIC_SETS_OUT_OF_RANGE
=
1014
DE265_WARNING_SHORT_TERM_REF_PIC_SET_OUT_OF_RANGE
=
1015
DE265_WARNING_FAULTY_REFERENCE_PICTURE_LIST
=
1016
DE265_WARNING_EOSS_BIT_NOT_SET
=
1017
DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED
=
1018
DE265_WARNING_INVALID_CHROMA_FORMAT
=
1019
DE265_WARNING_SLICE_SEGMENT_ADDRESS_INVALID
=
1020
DE265_WARNING_DEPENDENT_SLICE_WITH_ADDRESS_ZERO
=
1021
DE265_WARNING_NUMBER_OF_THREADS_LIMITED_TO_MAXIMUM
=
1022
DE265_NON_EXISTING_LT_REFERENCE_CANDIDATE_IN_SLICE_HEADER
=
1023
DE265_WARNING_CANNOT_APPLY_SAO_OUT_OF_MEMORY
=
1024
DE265_WARNING_SPS_MISSING_CANNOT_DECODE_SEI
=
1025
DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA
=
1026
class
libde265error
(
IntEnum
):
DE265_OK
=
0
DE265_ERROR_NO_SUCH_FILE
=
1
DE265_ERROR_COEFFICIENT_OUT_OF_IMAGE_BOUNDS
=
4
DE265_ERROR_CHECKSUM_MISMATCH
=
5
DE265_ERROR_CTB_OUTSIDE_IMAGE_AREA
=
6
DE265_ERROR_OUT_OF_MEMORY
=
7
DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE
=
8
DE265_ERROR_IMAGE_BUFFER_FULL
=
9
DE265_ERROR_CANNOT_START_THREADPOOL
=
10
DE265_ERROR_LIBRARY_INITIALIZATION_FAILED
=
11
DE265_ERROR_LIBRARY_NOT_INITIALIZED
=
12
DE265_ERROR_WAITING_FOR_INPUT_DATA
=
13
DE265_ERROR_CANNOT_PROCESS_SEI
=
14
DE265_ERROR_PARAMETER_PARSING
=
15
DE265_ERROR_NO_INITIAL_SLICE_HEADER
=
16
DE265_ERROR_PREMATURE_END_OF_SLICE
=
17
DE265_ERROR_UNSPECIFIED_DECODING_ERROR
=
18
DE265_ERROR_NOT_IMPLEMENTED_YET
=
502
DE265_WARNING_NO_WPP_CANNOT_USE_MULTITHREADING
=
1000
DE265_WARNING_WARNING_BUFFER_FULL
=
1001
DE265_WARNING_PREMATURE_END_OF_SLICE_SEGMENT
=
1002
DE265_WARNING_INCORRECT_ENTRY_POINT_OFFSET
=
1003
DE265_WARNING_CTB_OUTSIDE_IMAGE_AREA
=
1004
DE265_WARNING_SPS_HEADER_INVALID
=
1005
DE265_WARNING_PPS_HEADER_INVALID
=
1006
DE265_WARNING_SLICEHEADER_INVALID
=
1007
DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING
=
1008
DE265_WARNING_NONEXISTING_PPS_REFERENCED
=
1009
DE265_WARNING_NONEXISTING_SPS_REFERENCED
=
1010
DE265_WARNING_BOTH_PREDFLAGS_ZERO
=
1011
DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED
=
1012
DE265_WARNING_NUMMVP_NOT_EQUAL_TO_NUMMVQ
=
1013
DE265_WARNING_NUMBER_OF_SHORT_TERM_REF_PIC_SETS_OUT_OF_RANGE
=
1014
DE265_WARNING_SHORT_TERM_REF_PIC_SET_OUT_OF_RANGE
=
1015
DE265_WARNING_FAULTY_REFERENCE_PICTURE_LIST
=
1016
DE265_WARNING_EOSS_BIT_NOT_SET
=
1017
DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED
=
1018
DE265_WARNING_INVALID_CHROMA_FORMAT
=
1019
DE265_WARNING_SLICE_SEGMENT_ADDRESS_INVALID
=
1020
DE265_WARNING_DEPENDENT_SLICE_WITH_ADDRESS_ZERO
=
1021
DE265_WARNING_NUMBER_OF_THREADS_LIMITED_TO_MAXIMUM
=
1022
DE265_NON_EXISTING_LT_REFERENCE_CANDIDATE_IN_SLICE_HEADER
=
1023
DE265_WARNING_CANNOT_APPLY_SAO_OUT_OF_MEMORY
=
1024
DE265_WARNING_SPS_MISSING_CANNOT_DECODE_SEI
=
1025
DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA
=
1026
libde265
=
ctypes
.
cdll
.
LoadLibrary
(
"
libde265.so.0
"
)
...
...
@@ -117,7 +133,7 @@ class Decoder:
def
__del__
(
self
):
libde265
.
de265_free_decoder
(
self
.
ctx_
)
def
get_error_str
(
self
,
code
):
return
libde265
.
de265_get_error_text
(
code
).
decode
(
"
ascii
"
)
...
...
@@ -148,21 +164,21 @@ class Decoder:
def
decode
(
self
):
err
=
libde265
.
de265_decode
(
self
.
ctx_
,
self
.
more_
)
if
err
and
err
!=
DE265_ERROR_WAITING_FOR_INPUT_DATA
:
if
err
and
err
!=
libde265error
.
DE265_ERROR_WAITING_FOR_INPUT_DATA
:
raise
Exception
(
self
.
get_error_str
(
err
))
return
self
.
more_
.
value
!=
0
def
flush_data
(
self
):
libde265
.
flush_data
(
self
.
ctx_
)
err
=
libde265
.
de265_flush_data
(
self
.
ctx_
)
if
err
:
raise
Exception
(
self
.
get_error_str
(
err
))
def
get_next_picture
(
self
):
'''
Returns next decoded frame. Image in YC
rCb
format. If no frame available
Returns next decoded frame. Image in YC
bCr
format. If no frame available
returns None.
TODO: Skimage
'
s ycrcb2rgb() does not look correct. Is Cr/Cb channel
created correctly?
'''
img
=
libde265
.
de265_get_next_picture
(
self
.
ctx_
)
...
...
@@ -172,20 +188,19 @@ class Decoder:
res
=
np
.
zeros
((
self
.
size_
[
0
],
self
.
size_
[
1
],
3
),
dtype
=
np
.
uint8
)
for
c
in
range
(
0
,
3
):
size
=
(
libde265
.
de265_get_image_height
(
img
,
c
),
libde265
.
de265_get_image_width
(
img
,
c
))
bpp
=
libde265
.
de265_get_bits_per_pixel
(
img
,
c
)
img_ptr
=
libde265
.
de265_get_image_plane
(
img
,
c
,
self
.
out_stride_
)
scale_y
=
self
.
size_
[
0
]
/
size
[
0
]
scale_x
=
self
.
size_
[
1
]
/
size
[
1
]
size
=
(
libde265
.
de265_get_image_height
(
img
,
c
),
libde265
.
de265_get_image_width
(
img
,
c
))
bpp
=
libde265
.
de265_get_bits_per_pixel
(
img
,
c
)
if
bpp
!=
8
:
raise
NotImplementedError
(
"
unsupported bits per pixel %i
"
%
bpp
)
if
scale_x
!=
scale_y
:
raise
NotImplementedError
(
"
unsupported subsampling
"
)
img_ptr
=
libde265
.
de265_get_image_plane
(
img
,
c
,
self
.
out_stride_
)
ch
=
np
.
frombuffer
(
img_ptr
[:
size
[
0
]
*
size
[
1
]],
dtype
=
np
.
uint8
)
ch
.
shape
=
size
channel
=
np
.
asarray
(
bytearray
(
img_ptr
[:
size
[
0
]
*
size
[
1
]]),
dtype
=
np
.
uint8
)
channel
.
shape
=
size
res
[:,:,
c
]
=
(
rescale
(
channel
,
scale_x
)
*
255
).
astype
(
np
.
uint8
)
res
[:,:,
c
]
=
resize
(
ch
,
self
.
size_
)
return
res
\ No newline at end of file
return
res
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