Skip to content

Commit

Permalink
feat: avs3 flv
Browse files Browse the repository at this point in the history
  • Loading branch information
ireader committed Jul 8, 2023
1 parent 15bef50 commit 7d8cb39
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 0 deletions.
37 changes: 37 additions & 0 deletions libflv/include/avswg-avs3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef _avswg_avs3_h_
#define _avswg_avs3_h_

// http://standard.avswg.org.cn/avs3_download/

#include <stdint.h>
#include <stddef.h>

#if defined(__cplusplus)
extern "C" {
#endif

struct avswg_avs3_t
{
uint32_t version : 8;
uint32_t sequence_header_length : 16;
uint32_t library_dependency_idc : 2;

uint8_t sequence_header[2 * 1024]; // bytes: sequence_header_length
};
/// Create avs3 codec configuration record from bitstream
/// @param[in] data avs3 bitstream format(00 00 01 B0)
/// @return 0-ok, other-error
int avswg_avs3_decoder_configuration_record_init(struct avswg_avs3_t* avs3, const void* data, size_t bytes);

// load avs3 from Avs3DecoderConfigurationRecord
int avswg_avs3_decoder_configuration_record_load(const uint8_t* data, size_t bytes, struct avswg_avs3_t* avs3);

int avswg_avs3_decoder_configuration_record_save(const struct avswg_avs3_t* avs3, uint8_t* data, size_t bytes);

int avswg_avs3_codecs(const struct avswg_avs3_t* avs3, char* codecs, size_t bytes);

#if defined(__cplusplus)
}
#endif

#endif /* !_avswg_avs3_h_ */
3 changes: 3 additions & 0 deletions libflv/include/flv-muxer.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ int flv_muxer_hevc(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t
/// @param[in] data av1 low overhead bitstream format
int flv_muxer_av1(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t pts, uint32_t dts);

/// @param[in] data avs3 bitstream (00 00 01 B0 ...)
int flv_muxer_avs3(flv_muxer_t* muxer, const void* data, size_t bytes, uint32_t pts, uint32_t dts);

struct flv_metadata_t
{
int audiocodecid;
Expand Down
90 changes: 90 additions & 0 deletions libflv/source/avswg-avs3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include "avswg-avs3.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>

#define AVS3_VIDEO_SEQUENCE_START 0xB0

/*
aligned(8) class Avs3DecoderConfigurationRecord {
unsigned int(8) configurationVersion = 1;
unsigned int(16) sequence_header_length;
bit(8*sequence_header_length) sequence_header;
bit(6) reserved = '111111'b;
unsigned int(2) library_dependency_idc;
}
*/

int avswg_avs3_decoder_configuration_record_load(const uint8_t* data, size_t bytes, struct avswg_avs3_t* avs3)
{
if (bytes < 4) return -1;
assert(1 == data[0]);
avs3->version = data[0];
avs3->sequence_header_length = (((uint32_t)data[1]) << 8) | data[2];
if (avs3->sequence_header_length + 4 > bytes || avs3->sequence_header_length > sizeof(avs3->sequence_header))
return -1;

memcpy(avs3->sequence_header, data + 3, avs3->sequence_header_length);
avs3->library_dependency_idc = data[avs3->sequence_header_length + 3] & 0x03;
return avs3->sequence_header_length + 4;
}

int avswg_avs3_decoder_configuration_record_save(const struct avswg_avs3_t* avs3, uint8_t* data, size_t bytes)
{
if (bytes < 4 + avs3->sequence_header_length) return -1;

data[0] = 1; // configurationVersion
data[1] = (uint8_t)(avs3->sequence_header_length >> 8);
data[2] = (uint8_t)(avs3->sequence_header_length);
memcpy(data + 3, avs3->sequence_header, avs3->sequence_header_length);
data[3 + avs3->sequence_header_length] = 0xFC | (uint8_t)(avs3->library_dependency_idc);
return (int)(4 + avs3->sequence_header_length);
}

int avswg_avs3_codecs(const struct avswg_avs3_t* avs3, char* codecs, size_t bytes)
{
// // AVS3-P6: Annex-A
return snprintf(codecs, bytes, "avs3.%02x.%02x", (unsigned int)(avs3->sequence_header_length > 6 ? avs3->sequence_header[4] : 0), (unsigned int)(avs3->sequence_header_length > 6 ? avs3->sequence_header[5] : 0));
}

int avswg_avs3_decoder_configuration_record_init(struct avswg_avs3_t* avs3, const void* data, size_t bytes)
{
size_t i;
const uint8_t* p;

p = data;
if (bytes < 8 || 0 != p[0] || 0 != p[1] || 1 != p[2] || AVS3_VIDEO_SEQUENCE_START != p[3])
return -1;

for (i = 0; i + 1 < sizeof(avs3->sequence_header)
&& (i < 4 || i + 3 >= bytes || 0 != p[i] || 0 != p[i + 1] || 1 != p[i + 2])
; i++)
{
avs3->sequence_header[i] = p[i];
}

avs3->version = 1;
avs3->sequence_header_length = (uint32_t)i;
avs3->library_dependency_idc = 0;
return 0;
}

#if defined(_DEBUG) || defined(DEBUG)
void avswg_avs3_test(void)
{
const unsigned char src[] = {
0x01,0x00,0x1d,0x00,0x00,0x01,0xb0,0x20,0x44,0x88,0xf0,0x11,0x0e,0x13,0x16,0x87,0x2b,
0x10,0x00,0x20,0x10,0xcf,0xcf,0xc1,0x06,0x14,0x10,0x10,0x67,0x0f,0x04,0x48,0xfc,
};
unsigned char data[sizeof(src)];

struct avswg_avs3_t avs3;
assert(sizeof(src) == avswg_avs3_decoder_configuration_record_load(src, sizeof(src), &avs3));
assert(1 == avs3.version && 0x1d == avs3.sequence_header_length && 0 == avs3.library_dependency_idc);
assert(sizeof(src) == avswg_avs3_decoder_configuration_record_save(&avs3, data, sizeof(data)));
assert(0 == memcmp(src, data, sizeof(src)));

avswg_avs3_codecs(&avs3, (char*)data, sizeof(data));
assert(0 == memcmp("avs3.20.44", data, 10));
}
#endif
49 changes: 49 additions & 0 deletions libflv/source/flv-muxer.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "mpeg4-avc.h"
#include "mpeg4-vvc.h"
#include "mpeg4-hevc.h"
#include "avswg-avs3.h"
#include "mp3-header.h"
#include "opus-head.h"

Expand All @@ -38,6 +39,7 @@ struct flv_muxer_t
struct mpeg4_avc_t avc;
struct mpeg4_hevc_t hevc;
struct mpeg4_vvc_t vvc;
struct avswg_avs3_t avs3;
} v;
int vcl; // 0-non vcl, 1-idr, 2-p/b
int update; // avc/hevc sequence header update
Expand Down Expand Up @@ -455,6 +457,53 @@ int flv_muxer_av1(flv_muxer_t* flv, const void* data, size_t bytes, uint32_t pts
return 0;
}

int flv_muxer_avs3(flv_muxer_t* flv, const void* data, size_t bytes, uint32_t pts, uint32_t dts)
{
int r;
int m;
struct flv_video_tag_header_t video;

if ((size_t)flv->capacity < bytes + 5 + sizeof(flv->v.avs3) /*AVS3DecoderConfigurationRecord*/)
{
if (0 != flv_muxer_alloc(flv, bytes + sizeof(flv->v.avs3)))
return -ENOMEM;
}

video.codecid = FLV_VIDEO_H266; // codec 14, same as H.266
if (0 == flv->video_sequence_header)
{
// load avs information
r = avswg_avs3_decoder_configuration_record_init(&flv->v.avs3, data, bytes);
if (0 != r || flv->v.avs3.sequence_header_length < 1)
return 0 == r ? -1 : r;

video.cts = 0;
video.keyframe = 1; // keyframe
video.avpacket = FLV_SEQUENCE_HEADER;
flv_video_tag_header_write(&video, flv->ptr + flv->bytes, flv->capacity - flv->bytes);
m = avswg_avs3_decoder_configuration_record_save(&flv->v.avs3, flv->ptr + flv->bytes + 5, flv->capacity - flv->bytes - 5);
if (m <= 0)
return -1; // invalid data

flv->video_sequence_header = 1; // once only
assert(flv->bytes + m + 5 <= flv->capacity);
r = flv->handler(flv->param, FLV_TYPE_VIDEO, flv->ptr + flv->bytes, m + 5, dts);
if (0 != r) return r;
}

// has video frame
if (flv->video_sequence_header)
{
video.cts = pts - dts;
video.keyframe = 1 == flv->vcl ? FLV_VIDEO_KEY_FRAME : FLV_VIDEO_INTER_FRAME;
video.avpacket = FLV_AVPACKET;
flv_video_tag_header_write(&video, flv->ptr, flv->capacity);
memcpy(flv->ptr + 5, data, bytes);
return flv->handler(flv->param, FLV_TYPE_VIDEO, flv->ptr, bytes + 5, dts);
}
return 0;
}

int flv_muxer_metadata(flv_muxer_t* flv, const struct flv_metadata_t* metadata)
{
uint8_t* ptr, *end;
Expand Down

0 comments on commit 7d8cb39

Please sign in to comment.