Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
小白菜888
Ffmpeg
提交
3ee21785
F
Ffmpeg
项目概览
小白菜888
/
Ffmpeg
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
Ffmpeg
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3ee21785
编写于
7月 23, 2015
作者:
T
Tom Butterworth
提交者:
Vittorio Giovara
7月 27, 2015
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support the Hap chunked frame format
Signed-off-by:
N
Vittorio Giovara
<
vittorio.giovara@gmail.com
>
上级
43dd0047
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
414 addition
and
97 deletion
+414
-97
libavcodec/Makefile
libavcodec/Makefile
+2
-2
libavcodec/hap.h
libavcodec/hap.h
+35
-3
libavcodec/hapdec.c
libavcodec/hapdec.c
+214
-59
libavcodec/hapenc.c
libavcodec/hapenc.c
+159
-32
libavcodec/version.h
libavcodec/version.h
+1
-1
tests/fate/video.mak
tests/fate/video.mak
+3
-0
未找到文件。
libavcodec/Makefile
浏览文件 @
3ee21785
...
...
@@ -243,8 +243,8 @@ OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
OBJS-$(CONFIG_H264_NVENC_ENCODER)
+=
nvenc_h264.o
OBJS-$(CONFIG_H264_QSV_DECODER)
+=
qsvdec_h2645.o
OBJS-$(CONFIG_H264_QSV_ENCODER)
+=
qsvenc_h264.o
OBJS-$(CONFIG_HAP_DECODER)
+=
hapdec.o
OBJS-$(CONFIG_HAP_ENCODER)
+=
hapenc.o
OBJS-$(CONFIG_HAP_DECODER)
+=
hapdec.o
hap.o
OBJS-$(CONFIG_HAP_ENCODER)
+=
hapenc.o
hap.o
OBJS-$(CONFIG_HEVC_DECODER)
+=
hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o
\
hevc_cabac.o hevc_refs.o hevcpred.o
\
hevcdsp.o hevc_filter.o hevc_parse.o hevc_data.o
...
...
libavcodec/hap.h
浏览文件 @
3ee21785
/*
* Vidvox Hap
* Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
* Copyright (C) 2015 Tom Butterworth <bangnoise@gmail.com>
*
* This file is part of Libav.
*
...
...
@@ -41,20 +42,39 @@ enum HapCompressor {
HAP_COMP_COMPLEX
=
0xC0
,
};
enum
HapSectionType
{
HAP_ST_DECODE_INSTRUCTIONS
=
0x01
,
HAP_ST_COMPRESSOR_TABLE
=
0x02
,
HAP_ST_SIZE_TABLE
=
0x03
,
HAP_ST_OFFSET_TABLE
=
0x04
,
};
typedef
struct
HapChunk
{
enum
HapCompressor
compressor
;
int
compressed_offset
;
size_t
compressed_size
;
int
uncompressed_offset
;
size_t
uncompressed_size
;
}
HapChunk
;
typedef
struct
HapContext
{
AVClass
*
class
;
TextureDSPContext
dxtc
;
GetByteContext
gbc
;
int
section_type
;
/* Header type */
enum
HapTextureFormat
opt_tex_fmt
;
/* Texture type (encoder only) */
int
opt_chunk_count
;
/* User-requested chunk count (encoder only) */
int
chunk_count
;
HapChunk
*
chunks
;
int
*
chunk_results
;
/* Results from threaded operations */
int
tex_rat
;
/* Compression ratio */
const
uint8_t
*
tex_data
;
/* Compressed texture */
uint8_t
*
tex_buf
;
/*
Un
compressed texture */
uint8_t
*
tex_buf
;
/*
Buffer for
compressed texture */
size_t
tex_size
;
/* Size of the compressed texture */
uint8_t
*
snappied
;
/* Buffer interacting with snappy */
size_t
max_snappy
;
/* Maximum compressed size for snappy buffer */
int
slice_count
;
/* Number of slices for threaded operations */
...
...
@@ -63,4 +83,16 @@ typedef struct HapContext {
int
(
*
tex_fun
)(
uint8_t
*
dst
,
ptrdiff_t
stride
,
const
uint8_t
*
block
);
}
HapContext
;
/*
* Set the number of chunks in the frame. Returns 0 on success or an error if:
* - first_in_frame is 0 and the number of chunks has changed
* - any other error occurs
*/
int
ff_hap_set_chunk_count
(
HapContext
*
ctx
,
int
count
,
int
first_in_frame
);
/*
* Free resources associated with the context
*/
av_cold
void
ff_hap_free_context
(
HapContext
*
ctx
);
#endif
/* AVCODEC_HAP_H */
libavcodec/hapdec.c
浏览文件 @
3ee21785
/*
* Vidvox Hap decoder
* Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
* Copyright (C) 2015 Tom Butterworth <bangnoise@gmail.com>
*
* This file is part of Libav.
*
...
...
@@ -36,6 +37,7 @@
#include "bytestream.h"
#include "hap.h"
#include "internal.h"
#include "memory.h"
#include "snappy.h"
#include "texturedsp.h"
#include "thread.h"
...
...
@@ -43,85 +45,224 @@
/* The first three bytes are the size of the section past the header, or zero
* if the length is stored in the next long word. The fourth byte in the first
* long word indicates the type of the current section. */
static
int
parse_section_header
(
AVCodecContext
*
avctx
)
static
int
parse_section_header
(
GetByteContext
*
gbc
,
int
*
section_size
,
enum
HapSectionType
*
section_type
)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
GetByteContext
*
gbc
=
&
ctx
->
gbc
;
int
length
;
if
(
bytestream2_get_bytes_left
(
gbc
)
<
4
)
return
AVERROR_INVALIDDATA
;
length
=
bytestream2_get_le24
(
gbc
);
*
section_size
=
bytestream2_get_le24
(
gbc
);
*
section_type
=
bytestream2_get_byte
(
gbc
);
ctx
->
section_type
=
bytestream2_get_byte
(
gbc
);
if
(
length
==
0
)
{
if
(
*
section_size
==
0
)
{
if
(
bytestream2_get_bytes_left
(
gbc
)
<
4
)
return
AVERROR_INVALIDDATA
;
length
=
bytestream2_get_le32
(
gbc
);
*
section_size
=
bytestream2_get_le32
(
gbc
);
}
if
(
length
>
bytestream2_get_bytes_left
(
gbc
)
||
length
==
0
)
if
(
*
section_size
>
bytestream2_get_bytes_left
(
gbc
)
)
return
AVERROR_INVALIDDATA
;
else
return
0
;
}
static
int
hap_parse_decode_instructions
(
HapContext
*
ctx
,
int
size
)
{
GetByteContext
*
gbc
=
&
ctx
->
gbc
;
int
section_size
;
enum
HapSectionType
section_type
;
int
is_first_table
=
1
,
had_offsets
=
0
,
had_compressors
=
0
,
had_sizes
=
0
;
int
i
,
ret
;
while
(
size
>
0
)
{
int
stream_remaining
=
bytestream2_get_bytes_left
(
gbc
);
ret
=
parse_section_header
(
gbc
,
&
section_size
,
&
section_type
);
if
(
ret
!=
0
)
return
ret
;
size
-=
stream_remaining
-
bytestream2_get_bytes_left
(
gbc
);
return
length
;
switch
(
section_type
)
{
case
HAP_ST_COMPRESSOR_TABLE
:
ret
=
ff_hap_set_chunk_count
(
ctx
,
section_size
,
is_first_table
);
if
(
ret
!=
0
)
return
ret
;
for
(
i
=
0
;
i
<
section_size
;
i
++
)
{
ctx
->
chunks
[
i
].
compressor
=
bytestream2_get_byte
(
gbc
)
<<
4
;
}
had_compressors
=
1
;
is_first_table
=
0
;
break
;
case
HAP_ST_SIZE_TABLE
:
ret
=
ff_hap_set_chunk_count
(
ctx
,
section_size
/
4
,
is_first_table
);
if
(
ret
!=
0
)
return
ret
;
for
(
i
=
0
;
i
<
section_size
/
4
;
i
++
)
{
ctx
->
chunks
[
i
].
compressed_size
=
bytestream2_get_le32
(
gbc
);
}
had_sizes
=
1
;
is_first_table
=
0
;
break
;
case
HAP_ST_OFFSET_TABLE
:
ret
=
ff_hap_set_chunk_count
(
ctx
,
section_size
/
4
,
is_first_table
);
if
(
ret
!=
0
)
return
ret
;
for
(
i
=
0
;
i
<
section_size
/
4
;
i
++
)
{
ctx
->
chunks
[
i
].
compressed_offset
=
bytestream2_get_le32
(
gbc
);
}
had_offsets
=
1
;
is_first_table
=
0
;
break
;
default:
break
;
}
size
-=
section_size
;
}
if
(
!
had_sizes
||
!
had_compressors
)
return
AVERROR_INVALIDDATA
;
/* The offsets table is optional. If not present than calculate offsets by
* summing the sizes of preceding chunks. */
if
(
!
had_offsets
)
{
size_t
running_size
=
0
;
for
(
i
=
0
;
i
<
ctx
->
chunk_count
;
i
++
)
{
ctx
->
chunks
[
i
].
compressed_offset
=
running_size
;
running_size
+=
ctx
->
chunks
[
i
].
compressed_size
;
}
}
return
0
;
}
static
int
hap_can_use_tex_in_place
(
HapContext
*
ctx
)
{
int
i
;
size_t
running_offset
=
0
;
for
(
i
=
0
;
i
<
ctx
->
chunk_count
;
i
++
)
{
if
(
ctx
->
chunks
[
i
].
compressed_offset
!=
running_offset
||
ctx
->
chunks
[
i
].
compressor
!=
HAP_COMP_NONE
)
return
0
;
running_offset
+=
ctx
->
chunks
[
i
].
compressed_size
;
}
return
1
;
}
/* Prepare the texture to be decompressed */
static
int
setup_texture
(
AVCodecContext
*
avctx
,
size_t
length
)
static
int
hap_parse_frame_header
(
AVCodecContext
*
avctx
)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
GetByteContext
*
gbc
=
&
ctx
->
gbc
;
int64_t
snappy_size
;
int
section_size
;
enum
HapSectionType
section_type
;
const
char
*
compressorstr
;
int
ret
;
int
i
,
ret
;
ret
=
parse_section_header
(
gbc
,
&
section_size
,
&
section_type
);
if
(
ret
!=
0
)
return
ret
;
if
((
avctx
->
codec_tag
==
MKTAG
(
'H'
,
'a'
,
'p'
,
'1'
)
&&
(
ctx
->
section_type
&
0x0F
)
!=
HAP_FMT_RGBDXT1
)
||
(
avctx
->
codec_tag
==
MKTAG
(
'H'
,
'a'
,
'p'
,
'5'
)
&&
(
ctx
->
section_type
&
0x0F
)
!=
HAP_FMT_RGBADXT5
)
||
(
avctx
->
codec_tag
==
MKTAG
(
'H'
,
'a'
,
'p'
,
'Y'
)
&&
(
ctx
->
section_type
&
0x0F
)
!=
HAP_FMT_YCOCGDXT5
))
{
if
((
avctx
->
codec_tag
==
MKTAG
(
'H'
,
'a'
,
'p'
,
'1'
)
&&
(
section_type
&
0x0F
)
!=
HAP_FMT_RGBDXT1
)
||
(
avctx
->
codec_tag
==
MKTAG
(
'H'
,
'a'
,
'p'
,
'5'
)
&&
(
section_type
&
0x0F
)
!=
HAP_FMT_RGBADXT5
)
||
(
avctx
->
codec_tag
==
MKTAG
(
'H'
,
'a'
,
'p'
,
'Y'
)
&&
(
section_type
&
0x0F
)
!=
HAP_FMT_YCOCGDXT5
))
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Invalid texture format %#04x.
\n
"
,
ctx
->
section_type
&
0x0F
);
"Invalid texture format %#04x.
\n
"
,
section_type
&
0x0F
);
return
AVERROR_INVALIDDATA
;
}
switch
(
ctx
->
section_type
&
0xF0
)
{
switch
(
section_type
&
0xF0
)
{
case
HAP_COMP_NONE
:
/* Only DXTC texture compression */
ctx
->
tex_data
=
gbc
->
buffer
;
ctx
->
tex_size
=
length
;
compressorstr
=
"none"
;
break
;
case
HAP_COMP_SNAPPY
:
snappy_size
=
ff_snappy_peek_uncompressed_length
(
gbc
);
ret
=
av_reallocp
(
&
ctx
->
snappied
,
snappy_size
);
if
(
ret
<
0
)
{
return
ret
;
}
/* Uncompress the frame */
ret
=
ff_snappy_uncompress
(
gbc
,
ctx
->
snappied
,
&
snappy_size
);
if
(
ret
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Snappy uncompress error
\n
"
);
return
ret
;
ret
=
ff_hap_set_chunk_count
(
ctx
,
1
,
1
);
if
(
ret
==
0
)
{
ctx
->
chunks
[
0
].
compressor
=
section_type
&
0xF0
;
ctx
->
chunks
[
0
].
compressed_offset
=
0
;
ctx
->
chunks
[
0
].
compressed_size
=
section_size
;
}
ctx
->
tex_data
=
ctx
->
snappied
;
ctx
->
tex_size
=
snappy_size
;
if
(
ctx
->
chunks
[
0
].
compressor
==
HAP_COMP_NONE
)
{
compressorstr
=
"none"
;
}
else
{
compressorstr
=
"snappy"
;
}
break
;
case
HAP_COMP_COMPLEX
:
ret
=
parse_section_header
(
gbc
,
&
section_size
,
&
section_type
);
if
(
ret
==
0
&&
section_type
!=
HAP_ST_DECODE_INSTRUCTIONS
)
ret
=
AVERROR_INVALIDDATA
;
if
(
ret
==
0
)
ret
=
hap_parse_decode_instructions
(
ctx
,
section_size
);
compressorstr
=
"complex"
;
avpriv_request_sample
(
avctx
,
"Complex Hap compressor"
);
return
AVERROR_PATCHWELCOME
;
break
;
default:
av_log
(
avctx
,
AV_LOG_ERROR
,
"Invalid compressor mode %02X.
\n
"
,
ctx
->
section_type
);
ret
=
AVERROR_INVALIDDATA
;
break
;
}
if
(
ret
!=
0
)
return
ret
;
/* Check the frame is valid and read the uncompressed chunk sizes */
ctx
->
tex_size
=
0
;
for
(
i
=
0
;
i
<
ctx
->
chunk_count
;
i
++
)
{
HapChunk
*
chunk
=
&
ctx
->
chunks
[
i
];
/* Check the compressed buffer is valid */
if
(
chunk
->
compressed_offset
+
chunk
->
compressed_size
>
bytestream2_get_bytes_left
(
gbc
))
return
AVERROR_INVALIDDATA
;
/* Chunks are unpacked sequentially, ctx->tex_size is the uncompressed
* size thus far */
chunk
->
uncompressed_offset
=
ctx
->
tex_size
;
/* Fill out uncompressed size */
if
(
chunk
->
compressor
==
HAP_COMP_SNAPPY
)
{
GetByteContext
gbc_tmp
;
int64_t
uncompressed_size
;
bytestream2_init
(
&
gbc_tmp
,
gbc
->
buffer
+
chunk
->
compressed_offset
,
chunk
->
compressed_size
);
uncompressed_size
=
ff_snappy_peek_uncompressed_length
(
&
gbc_tmp
);
if
(
uncompressed_size
<
0
)
{
return
uncompressed_size
;
}
chunk
->
uncompressed_size
=
uncompressed_size
;
}
else
if
(
chunk
->
compressor
==
HAP_COMP_NONE
)
{
chunk
->
uncompressed_size
=
chunk
->
compressed_size
;
}
else
{
return
AVERROR_INVALIDDATA
;
}
ctx
->
tex_size
+=
chunk
->
uncompressed_size
;
}
av_log
(
avctx
,
AV_LOG_DEBUG
,
"%s compressor
\n
"
,
compressorstr
);
return
ret
;
}
static
int
decompress_chunks_thread
(
AVCodecContext
*
avctx
,
void
*
arg
,
int
chunk_nb
,
int
thread_nb
)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
HapChunk
*
chunk
=
&
ctx
->
chunks
[
chunk_nb
];
GetByteContext
gbc
;
uint8_t
*
dst
=
ctx
->
tex_buf
+
chunk
->
uncompressed_offset
;
bytestream2_init
(
&
gbc
,
ctx
->
gbc
.
buffer
+
chunk
->
compressed_offset
,
chunk
->
compressed_size
);
if
(
chunk
->
compressor
==
HAP_COMP_SNAPPY
)
{
int
ret
;
int64_t
uncompressed_size
=
ctx
->
tex_size
;
/* Uncompress the frame */
ret
=
ff_snappy_uncompress
(
&
gbc
,
dst
,
&
uncompressed_size
);
if
(
ret
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Snappy uncompress error
\n
"
);
return
ret
;
}
}
else
if
(
chunk
->
compressor
==
HAP_COMP_NONE
)
{
bytestream2_get_buffer
(
&
gbc
,
dst
,
chunk
->
compressed_size
);
}
return
0
;
}
...
...
@@ -167,19 +308,12 @@ static int hap_decode(AVCodecContext *avctx, void *data,
{
HapContext
*
ctx
=
avctx
->
priv_data
;
ThreadFrame
tframe
;
int
ret
,
length
;
int
ret
,
i
;
bytestream2_init
(
&
ctx
->
gbc
,
avpkt
->
data
,
avpkt
->
size
);
/* Check for section header */
length
=
parse_section_header
(
avctx
);
if
(
length
<
0
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Frame is too small.
\n
"
);
return
length
;
}
/* Prepare the texture buffer and decompress function */
ret
=
setup_texture
(
avctx
,
length
);
ret
=
hap_parse_frame_header
(
avctx
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -190,6 +324,27 @@ static int hap_decode(AVCodecContext *avctx, void *data,
return
ret
;
ff_thread_finish_setup
(
avctx
);
/* Unpack the DXT texture */
if
(
hap_can_use_tex_in_place
(
ctx
))
{
/* Only DXTC texture compression in a contiguous block */
ctx
->
tex_data
=
ctx
->
gbc
.
buffer
;
}
else
{
/* Perform the second-stage decompression */
ret
=
av_reallocp
(
&
ctx
->
tex_buf
,
ctx
->
tex_size
);
if
(
ret
<
0
)
return
ret
;
avctx
->
execute2
(
avctx
,
decompress_chunks_thread
,
NULL
,
ctx
->
chunk_results
,
ctx
->
chunk_count
);
for
(
i
=
0
;
i
<
ctx
->
chunk_count
;
i
++
)
{
if
(
ctx
->
chunk_results
[
i
]
<
0
)
return
ctx
->
chunk_results
[
i
];
}
ctx
->
tex_data
=
ctx
->
tex_buf
;
}
/* Use the decompress function on the texture, one block per thread */
avctx
->
execute2
(
avctx
,
decompress_texture_thread
,
tframe
.
f
,
NULL
,
ctx
->
slice_count
);
...
...
@@ -254,7 +409,7 @@ static av_cold int hap_close(AVCodecContext *avctx)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
av_freep
(
&
ctx
->
snappied
);
ff_hap_free_context
(
ctx
);
return
0
;
}
...
...
libavcodec/hapenc.c
浏览文件 @
3ee21785
/*
* Vidvox Hap encoder
* Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
* Copyright (C) 2015 Tom Butterworth <bangnoise@gmail.com>
*
* This file is part of Libav.
*
...
...
@@ -42,8 +43,14 @@
#include "internal.h"
#include "texturedsp.h"
/* A fixed header size allows to skip a memcpy */
#define HEADER_SIZE 8
#define HAP_MAX_CHUNKS 64
enum
HapHeaderLength
{
/* Short header: four bytes with a 24 bit size value */
HAP_HDR_SHORT
=
4
,
/* Long header: eight bytes with a 32 bit size value */
HAP_HDR_LONG
=
8
,
};
static
void
compress_texture
(
AVCodecContext
*
avctx
,
const
AVFrame
*
f
)
{
...
...
@@ -60,46 +67,151 @@ static void compress_texture(AVCodecContext *avctx, const AVFrame *f)
}
}
static
int
hap_encode
(
AVCodecContext
*
avctx
,
AVPacket
*
pkt
,
const
AVFrame
*
frame
,
int
*
got_packet
)
/* section_length does not include the header */
static
void
hap_write_section_header
(
PutByteContext
*
pbc
,
enum
HapHeaderLength
header_length
,
int
section_length
,
enum
HapSectionType
section_type
)
{
/* The first three bytes are the length of the section (not including the
* header) or zero if using an eight-byte header.
* For an eight-byte header, the length is in the last four bytes.
* The fourth byte stores the section type. */
bytestream2_put_le24
(
pbc
,
header_length
==
HAP_HDR_LONG
?
0
:
section_length
);
bytestream2_put_byte
(
pbc
,
section_type
);
if
(
header_length
==
HAP_HDR_LONG
)
{
bytestream2_put_le32
(
pbc
,
section_length
);
}
}
static
int
hap_compress_frame
(
AVCodecContext
*
avctx
,
uint8_t
*
dst
)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
size_t
final_size
=
ctx
->
max_snappy
;
int
ret
,
comp
=
HAP_COMP_SNAPPY
;
int
pktsize
=
FFMAX
(
ctx
->
tex_size
,
ctx
->
max_snappy
)
+
HEADER_SIZE
;
int
i
,
final_size
=
0
;
/* Allocate maximum size packet, shrink later. */
ret
=
ff_alloc_packet
(
pkt
,
pktsize
)
;
if
(
ret
<
0
)
return
ret
;
for
(
i
=
0
;
i
<
ctx
->
chunk_count
;
i
++
)
{
HapChunk
*
chunk
=
&
ctx
->
chunks
[
i
]
;
uint8_t
*
chunk_src
,
*
chunk_dst
;
int
ret
;
/* DXTC compression. */
compress_texture
(
avctx
,
frame
);
if
(
i
==
0
)
{
chunk
->
compressed_offset
=
0
;
}
else
{
chunk
->
compressed_offset
=
ctx
->
chunks
[
i
-
1
].
compressed_offset
+
ctx
->
chunks
[
i
-
1
].
compressed_size
;
}
chunk
->
uncompressed_size
=
ctx
->
tex_size
/
ctx
->
chunk_count
;
chunk
->
uncompressed_offset
=
i
*
chunk
->
uncompressed_size
;
chunk
->
compressed_size
=
ctx
->
max_snappy
;
chunk_src
=
ctx
->
tex_buf
+
chunk
->
uncompressed_offset
;
chunk_dst
=
dst
+
chunk
->
compressed_offset
;
/* Compress with snappy too, write directly on packet buffer. */
ret
=
snappy_compress
(
ctx
->
tex_buf
,
ctx
->
tex
_size
,
pkt
->
data
+
HEADER_SIZE
,
&
final
_size
);
ret
=
snappy_compress
(
chunk_src
,
chunk
->
uncompressed
_size
,
chunk_dst
,
&
chunk
->
compressed
_size
);
if
(
ret
!=
SNAPPY_OK
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"Snappy compress error.
\n
"
);
return
AVERROR_BUG
;
}
/* If there is no gain from snappy, just use the raw texture. */
if
(
final_size
>
ctx
->
tex_size
)
{
comp
=
HAP_COMP_NONE
;
if
(
chunk
->
compressed_size
>=
chunk
->
uncompressed_size
)
{
av_log
(
avctx
,
AV_LOG_VERBOSE
,
"Snappy buffer bigger than uncompressed (%lu > %lu bytes).
\n
"
,
final_size
,
ctx
->
tex_size
);
memcpy
(
pkt
->
data
+
HEADER_SIZE
,
ctx
->
tex_buf
,
ctx
->
tex_size
);
final_size
=
ctx
->
tex_size
;
"Snappy buffer bigger than uncompressed (%lu >= %lu bytes).
\n
"
,
chunk
->
compressed_size
,
chunk
->
uncompressed_size
);
memcpy
(
chunk_dst
,
chunk_src
,
chunk
->
uncompressed_size
);
chunk
->
compressor
=
HAP_COMP_NONE
;
chunk
->
compressed_size
=
chunk
->
uncompressed_size
;
}
else
{
chunk
->
compressor
=
HAP_COMP_SNAPPY
;
}
final_size
+=
chunk
->
compressed_size
;
}
return
final_size
;
}
static
int
hap_decode_instructions_length
(
HapContext
*
ctx
)
{
/* Second-Stage Compressor Table (one byte per entry)
* + Chunk Size Table (four bytes per entry)
* + headers for both sections (short versions)
* = chunk_count + (4 * chunk_count) + 4 + 4 */
return
(
5
*
ctx
->
chunk_count
)
+
8
;
}
static
int
hap_header_length
(
HapContext
*
ctx
)
{
/* Top section header (long version) */
int
length
=
HAP_HDR_LONG
;
if
(
ctx
->
chunk_count
>
1
)
{
/* Decode Instructions header (short) + Decode Instructions Container */
length
+=
HAP_HDR_SHORT
+
hap_decode_instructions_length
(
ctx
);
}
return
length
;
}
static
void
hap_write_frame_header
(
HapContext
*
ctx
,
uint8_t
*
dst
,
int
frame_length
)
{
PutByteContext
pbc
;
int
i
;
bytestream2_init_writer
(
&
pbc
,
dst
,
frame_length
);
if
(
ctx
->
chunk_count
==
1
)
{
/* Write a simple header */
hap_write_section_header
(
&
pbc
,
HAP_HDR_LONG
,
frame_length
-
8
,
ctx
->
chunks
[
0
].
compressor
|
ctx
->
opt_tex_fmt
);
}
else
{
/* Write a complex header with Decode Instructions Container */
hap_write_section_header
(
&
pbc
,
HAP_HDR_LONG
,
frame_length
-
8
,
HAP_COMP_COMPLEX
|
ctx
->
opt_tex_fmt
);
hap_write_section_header
(
&
pbc
,
HAP_HDR_SHORT
,
hap_decode_instructions_length
(
ctx
),
HAP_ST_DECODE_INSTRUCTIONS
);
hap_write_section_header
(
&
pbc
,
HAP_HDR_SHORT
,
ctx
->
chunk_count
,
HAP_ST_COMPRESSOR_TABLE
);
for
(
i
=
0
;
i
<
ctx
->
chunk_count
;
i
++
)
{
bytestream2_put_byte
(
&
pbc
,
ctx
->
chunks
[
i
].
compressor
>>
4
);
}
hap_write_section_header
(
&
pbc
,
HAP_HDR_SHORT
,
ctx
->
chunk_count
*
4
,
HAP_ST_SIZE_TABLE
);
for
(
i
=
0
;
i
<
ctx
->
chunk_count
;
i
++
)
{
bytestream2_put_le32
(
&
pbc
,
ctx
->
chunks
[
i
].
compressed_size
);
}
}
}
static
int
hap_encode
(
AVCodecContext
*
avctx
,
AVPacket
*
pkt
,
const
AVFrame
*
frame
,
int
*
got_packet
)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
int
header_length
=
hap_header_length
(
ctx
);
int
final_data_size
,
ret
;
int
pktsize
=
FFMAX
(
ctx
->
tex_size
,
ctx
->
max_snappy
*
ctx
->
chunk_count
)
+
header_length
;
/* Allocate maximum size packet, shrink later. */
ret
=
ff_alloc_packet
(
pkt
,
pktsize
);
if
(
ret
<
0
)
return
ret
;
/* DXTC compression. */
compress_texture
(
avctx
,
frame
);
/* Compress (using Snappy) the frame */
final_data_size
=
hap_compress_frame
(
avctx
,
pkt
->
data
+
header_length
);
if
(
final_data_size
<
0
)
return
final_data_size
;
/* Write header at the start. */
AV_WL24
(
pkt
->
data
,
0
);
AV_WL32
(
pkt
->
data
+
4
,
final_size
);
pkt
->
data
[
3
]
=
comp
|
ctx
->
section_type
;
hap_write_frame_header
(
ctx
,
pkt
->
data
,
final_data_size
+
header_length
);
av_shrink_packet
(
pkt
,
final_
size
+
HEADER_SIZE
);
av_shrink_packet
(
pkt
,
final_
data_size
+
header_length
);
pkt
->
flags
|=
AV_PKT_FLAG_KEY
;
*
got_packet
=
1
;
return
0
;
...
...
@@ -109,6 +221,7 @@ static av_cold int hap_init(AVCodecContext *avctx)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
int
ratio
;
int
corrected_chunk_count
;
int
ret
=
av_image_check_size
(
avctx
->
width
,
avctx
->
height
,
0
,
avctx
);
if
(
ret
<
0
)
{
...
...
@@ -125,7 +238,7 @@ static av_cold int hap_init(AVCodecContext *avctx)
ff_texturedspenc_init
(
&
ctx
->
dxtc
);
switch
(
ctx
->
section_type
&
0x0F
)
{
switch
(
ctx
->
opt_tex_fmt
)
{
case
HAP_FMT_RGBDXT1
:
ratio
=
8
;
avctx
->
codec_tag
=
MKTAG
(
'H'
,
'a'
,
'p'
,
'1'
);
...
...
@@ -142,7 +255,7 @@ static av_cold int hap_init(AVCodecContext *avctx)
ctx
->
tex_fun
=
ctx
->
dxtc
.
dxt5ys_block
;
break
;
default:
av_log
(
avctx
,
AV_LOG_ERROR
,
"Invalid format %02X
\n
"
,
ctx
->
section_type
);
av_log
(
avctx
,
AV_LOG_ERROR
,
"Invalid format %02X
\n
"
,
ctx
->
opt_tex_fmt
);
return
AVERROR_INVALIDDATA
;
}
...
...
@@ -150,7 +263,21 @@ static av_cold int hap_init(AVCodecContext *avctx)
* beforehand the final size of the uncompressed buffer. */
ctx
->
tex_size
=
FFALIGN
(
avctx
->
width
,
TEXTURE_BLOCK_W
)
*
FFALIGN
(
avctx
->
height
,
TEXTURE_BLOCK_H
)
*
4
/
ratio
;
ctx
->
max_snappy
=
snappy_max_compressed_length
(
ctx
->
tex_size
);
/* Round the chunk count to divide evenly on DXT block edges */
corrected_chunk_count
=
av_clip
(
ctx
->
opt_chunk_count
,
1
,
HAP_MAX_CHUNKS
);
while
((
ctx
->
tex_size
/
(
64
/
ratio
))
%
corrected_chunk_count
!=
0
)
{
corrected_chunk_count
--
;
}
if
(
corrected_chunk_count
!=
ctx
->
opt_chunk_count
)
{
av_log
(
avctx
,
AV_LOG_INFO
,
"%d chunks requested but %d used.
\n
"
,
ctx
->
opt_chunk_count
,
corrected_chunk_count
);
}
ret
=
ff_hap_set_chunk_count
(
ctx
,
corrected_chunk_count
,
1
);
if
(
ret
!=
0
)
return
ret
;
ctx
->
max_snappy
=
snappy_max_compressed_length
(
ctx
->
tex_size
/
corrected_chunk_count
);
ctx
->
tex_buf
=
av_malloc
(
ctx
->
tex_size
);
if
(
!
ctx
->
tex_buf
)
...
...
@@ -163,7 +290,7 @@ static av_cold int hap_close(AVCodecContext *avctx)
{
HapContext
*
ctx
=
avctx
->
priv_data
;
av_freep
(
&
ctx
->
tex_buf
);
ff_hap_free_context
(
ctx
);
return
0
;
}
...
...
@@ -171,11 +298,11 @@ static av_cold int hap_close(AVCodecContext *avctx)
#define OFFSET(x) offsetof(HapContext, x)
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static
const
AVOption
options
[]
=
{
{
"format"
,
NULL
,
OFFSET
(
section_type
),
AV_OPT_TYPE_INT
,
{
.
i64
=
HAP_FMT_RGBDXT1
},
HAP_FMT_RGBDXT1
,
HAP_FMT_YCOCGDXT5
,
FLAGS
,
"format"
},
{
"format"
,
NULL
,
OFFSET
(
opt_tex_fmt
),
AV_OPT_TYPE_INT
,
{
.
i64
=
HAP_FMT_RGBDXT1
},
HAP_FMT_RGBDXT1
,
HAP_FMT_YCOCGDXT5
,
FLAGS
,
"format"
},
{
"hap"
,
"Hap 1 (DXT1 textures)"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
HAP_FMT_RGBDXT1
},
0
,
0
,
FLAGS
,
"format"
},
{
"hap_alpha"
,
"Hap Alpha (DXT5 textures)"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
HAP_FMT_RGBADXT5
},
0
,
0
,
FLAGS
,
"format"
},
{
"hap_q"
,
"Hap Q (DXT5-YCoCg textures)"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
HAP_FMT_YCOCGDXT5
},
0
,
0
,
FLAGS
,
"format"
},
{
"chunks"
,
"chunk count"
,
OFFSET
(
opt_chunk_count
),
AV_OPT_TYPE_INT
,
{.
i64
=
1
},
1
,
HAP_MAX_CHUNKS
,
FLAGS
,
},
{
NULL
},
};
...
...
libavcodec/version.h
浏览文件 @
3ee21785
...
...
@@ -30,7 +30,7 @@
#define LIBAVCODEC_VERSION_MAJOR 56
#define LIBAVCODEC_VERSION_MINOR 35
#define LIBAVCODEC_VERSION_MICRO
0
#define LIBAVCODEC_VERSION_MICRO
1
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
...
...
tests/fate/video.mak
浏览文件 @
3ee21785
...
...
@@ -169,6 +169,9 @@ fate-hap5: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hap5.mov
FATE_HAP
+=
fate-hapy
fate-hapy
:
CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy.mov
FATE_HAP
+=
fate-hap-chunk
fate-hap-chunk
:
CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy-12-chunks.mov
FATE_SAMPLES_AVCONV-$(call
DEMDEC,
MOV,
HAP)
+=
$(FATE_HAP)
fate-hap
:
$(FATE_HAP)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录