Skip to content

Commit

Permalink
Feature/262 (szatmary#31)
Browse files Browse the repository at this point in the history
* Support for h262 parsing
* Support for parsing out of order frames
  • Loading branch information
szatmary authored Jun 20, 2018
1 parent 5ca7cd0 commit e5f8a74
Show file tree
Hide file tree
Showing 32 changed files with 652 additions and 564 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ party
rtmpspit
rollup
sccdump
vttdump
vttsegmenter

# Autogenerated files
src/eia608_from_utf8.c
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ else()
endif()

set(CAPTION_SOURCES
src/avc.c
src/caption.c
src/cea708.c
src/eia608.c
src/eia608_charmap.c
src/eia608_from_utf8.c
src/mpeg.c
src/scc.c
src/srt.c
src/utf8.c
Expand All @@ -61,11 +61,11 @@ set(CAPTION_SOURCES
)

set(CAPTION_HEADERS
caption/avc.h
caption/caption.h
caption/cea708.h
caption/eia608.h
caption/eia608_charmap.h
caption/mpeg.h
caption/scc.h
caption/srt.h
caption/utf8.h
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# version
v0.7
v0.8
Matthew Szatmary m3u8@twitch.tv / matt@szatmary.org

# libcaption

libcaption is a small library written in C to aid in the creating and parsing of closed caption data for use in the twitch player, open sourced under the MIT license to use within community developed broadcast tools. To maintain consistency across platforms libcaption aims to implement a subset of EIA608, CEA708 as supported by the Apple iOS platform.
libcaption is a library written in C to aid in the creating and parsing of closed caption data, open sourced under the MIT license to use within community developed broadcast tools. To maintain consistency across platforms libcaption aims to implement a subset of EIA608, CEA708 as supported by the Apple iOS platform.

608 support is currently limited to encoding and decoding the necessary control and preamble codes as well as support for the Basic North American, Special North American and Extended Western European character sets.

Expand Down Expand Up @@ -37,8 +37,8 @@ H.264 utility functions are limited to wrapping the 708 payload into a SEI NALU.
* WEG = Extended Western European character set : German/Danish

## Limitations
Current B-frame support is minimal. libcaption ensures no re-ordering of captions is required
on playback. But caption parsing with out of order frames behaviour is currently undefined
Current B-frame support for caption creation is minimal. libcaption ensures no re-ordering of captions is required
on playback.

## Build Directions
# Mac Os/Linux
Expand Down
2 changes: 1 addition & 1 deletion caption/caption.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ typedef signed int ssize_t;
#endif

typedef enum {
LIBCAPTION_OK = 1,
LIBCAPTION_ERROR = 0,
LIBCAPTION_OK = 1,
LIBCAPTION_READY = 2
} libcaption_stauts_t;

Expand Down
11 changes: 8 additions & 3 deletions caption/cea708.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ typedef struct {
uint8_t user_data_type_code;
uint8_t directv_user_data_length;
user_data_t user_data;
double timestamp;
} cea708_t;

const static uint32_t GA94 = (('G' << 24) | ('A' << 16) | ('9' << 8) | '4');
Expand All @@ -92,15 +93,19 @@ const static uint32_t DTG1 = (('D' << 24) | ('T' << 16) | ('G' << 8) | '1');
/*! \brief
\param
*/
int cea708_init(cea708_t* cea708); // will confgure using HLS compatiable defaults
int cea708_init(cea708_t* cea708, double timestamp); // will confgure using HLS compatiable defaults
/*! \brief
\param
*/
int cea708_parse(uint8_t* data, size_t size, cea708_t* cea708);
libcaption_stauts_t cea708_parse_h264(const uint8_t* data, size_t size, cea708_t* cea708);
/*! \brief
\param
*/
libcaption_stauts_t cea708_to_caption_frame(caption_frame_t* frame, cea708_t* cea708, double pts);
libcaption_stauts_t cea708_parse_h262(const uint8_t* data, size_t size, cea708_t* cea708);
/*! \brief
\param
*/
libcaption_stauts_t cea708_to_caption_frame(caption_frame_t* frame, cea708_t* cea708);
/*! \brief
\param
*/
Expand Down
107 changes: 47 additions & 60 deletions caption/avc.h → caption/mpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
/* THE SOFTWARE. */
/**********************************************************************************************/
#ifndef LIBCAPTION_AVC_H
#define LIBCAPTION_AVC_H
#ifndef LIBCAPTION_MPEG_H
#define LIBCAPTION_MPEG_H
#ifdef __cplusplus
extern "C" {
#endif
Expand All @@ -31,21 +31,46 @@ extern "C" {
#include "cea708.h"
#include "scc.h"
#include <float.h>
#include <stddef.h>
////////////////////////////////////////////////////////////////////////////////
#define MAX_NALU_SIZE (4 * 1024 * 1024)
#define STREAM_TYPE_H262 0x02
#define STREAM_TYPE_H264 0x1B
#define STREAM_TYPE_H265 0x24
#define H262_SEI_PACKET 0xB2
#define H264_SEI_PACKET 0x06
#define H265_SEI_PACKET 0x27 // There is also 0x28
#define MAX_NALU_SIZE (6 * 1024 * 1024)
#define MAX_REFRENCE_FRAMES 64
typedef struct {
size_t size;
uint8_t data[MAX_NALU_SIZE];
} avcnalu_t;
uint8_t data[MAX_NALU_SIZE + 1];
double dts, cts;
libcaption_stauts_t status;
// Priority queue for out of order frame processing
// Should probablly be a linked list
size_t front;
size_t latent;
cea708_t cea708[MAX_REFRENCE_FRAMES];
} mpeg_bitstream_t;

void avcnalu_init(avcnalu_t* nalu);
int avcnalu_parse_annexb(avcnalu_t* nalu, const uint8_t** data, size_t* size);
static inline uint8_t avcnalu_type(avcnalu_t* nalu) { return nalu->data[0] & 0x1F; }
static inline uint8_t* avcnalu_data(avcnalu_t* nalu) { return &nalu->data[0]; }
static inline size_t avcnalu_size(avcnalu_t* nalu) { return nalu->size; }
void mpeg_bitstream_init(mpeg_bitstream_t* packet);
////////////////////////////////////////////////////////////////////////////////
// TODO make convenience functions for flv/mp4
/*! \brief
\param
*/
size_t mpeg_bitstream_parse(mpeg_bitstream_t* packet, caption_frame_t* frame, const uint8_t* data, size_t size, unsigned stream_type, double dts, double cts);
/*! \brief
\param
*/
static inline libcaption_stauts_t mpeg_bitstream_status(mpeg_bitstream_t* packet) { return packet->status; }
/*! \brief
Flushes latent packets caused by out or order frames.
Returns number of latent frames remaining, 0 when complete;
\param
*/
size_t mpeg_bitstream_flush(mpeg_bitstream_t* packet, caption_frame_t* frame);
////////////////////////////////////////////////////////////////////////////////
typedef struct _sei_message_t sei_message_t;

typedef enum {
sei_type_buffering_period = 0,
sei_type_pic_timing = 1,
Expand All @@ -71,18 +96,22 @@ typedef enum {
sei_type_stereo_video_info = 21,
} sei_msgtype_t;
////////////////////////////////////////////////////////////////////////////////
// time in seconds
typedef struct _sei_message_t {
size_t size;
sei_msgtype_t type;
struct _sei_message_t* next;
} sei_message_t;

typedef struct {
double dts;
double cts;
double timestamp;
sei_message_t* head;
sei_message_t* tail;
} sei_t;

/*! \brief
\param
*/
void sei_init(sei_t* sei);
void sei_init(sei_t* sei, double timestamp);
/*! \brief
\param
*/
Expand All @@ -98,22 +127,7 @@ void sei_message_append(sei_t* sei, sei_message_t* msg);
/*! \brief
\param
*/
static inline double sei_dts(sei_t* sei) { return sei->dts; }
static inline double sei_cts(sei_t* sei) { return sei->cts; }
static inline double sei_pts(sei_t* sei) { return sei->dts + sei->cts; }
/*! \brief
\param
*/
int sei_parse_nalu(sei_t* sei, const uint8_t* data, size_t size, double dts, double cts);
/*! \brief
\param
*/
// TODO add dts,cts to nalu
static inline int sei_parse_avcnalu(sei_t* sei, avcnalu_t* nalu, double dts, double cts) { return sei_parse_nalu(sei, avcnalu_data(nalu), avcnalu_size(nalu), dts, cts); }
/*! \brief
\param
*/
static inline int sei_finish(sei_t* sei) { return sei_parse_nalu(sei, 0, 0, 0.0, DBL_MAX); }
libcaption_stauts_t sei_parse(sei_t* sei, const uint8_t* data, size_t size, double timestamp);
/*! \brief
\param
*/
Expand Down Expand Up @@ -161,18 +175,6 @@ void sei_message_free(sei_message_t* msg);
/*! \brief
\param
*/
static inline int sei_decode_cea708(sei_message_t* msg, cea708_t* cea708)
{
if (sei_type_user_data_registered_itu_t_t35 == sei_message_type(msg)) {
return cea708_parse(sei_message_data(msg), sei_message_size(msg), cea708);
} else {
return 0;
}
}
////////////////////////////////////////////////////////////////////////////////
/*! \brief
\param
*/
size_t sei_render_size(sei_t* sei);
/*! \brief
\param
Expand All @@ -185,7 +187,7 @@ void sei_dump(sei_t* sei);
/*! \brief
\param
*/
void sei_dump_messages(sei_message_t* head);
void sei_dump_messages(sei_message_t* head, double timestamp);
////////////////////////////////////////////////////////////////////////////////
/*! \brief
\param
Expand All @@ -203,21 +205,6 @@ libcaption_stauts_t sei_from_caption_clear(sei_t* sei);
\param
*/
libcaption_stauts_t sei_to_caption_frame(sei_t* sei, caption_frame_t* frame);
/*! \brief
\param
*/
static inline libcaption_stauts_t avcnalu_to_caption_frame(caption_frame_t* frame, const uint8_t* data, size_t size, double dts, double cts)
{
sei_t sei;
libcaption_stauts_t err = LIBCAPTION_ERROR;

sei_init(&sei);
sei_parse_nalu(&sei, data, size, dts, cts);
err = sei_to_caption_frame(&sei, frame);
sei_free(&sei);

return err;
}
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
Expand Down
2 changes: 1 addition & 1 deletion caption/srt.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static inline utf8_char_t* srt_cue_data(srt_cue_t* cue) { return vtt_block_data(
/*! \brief
\param
*/
static inline srt_cue_t* srt_cue_from_caption_frame(caption_frame_t* frame, srt_t *srt) { return vtt_cue_from_caption_frame(frame, srt); };
static inline srt_cue_t* srt_cue_from_caption_frame(caption_frame_t* frame, srt_t* srt) { return vtt_cue_from_caption_frame(frame, srt); };

/*! \brief
\param
Expand Down
2 changes: 1 addition & 1 deletion caption/utf8.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ utf8_char_t* utf8_load_text_file(const char* path, size_t* size);
Compares 2 strings up to max len
*/
#ifndef strnstr
char *strnstr(const char *string1, const char *string2, size_t len);
char* strnstr(const char* string1, const char* string2, size_t len);
#endif

#ifdef __cplusplus
Expand Down
8 changes: 4 additions & 4 deletions caption/vtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ typedef struct _vtt_block_t {
// CUE-Only
double timestamp;
double duration; // -1.0 for no duration
char *cue_settings;
char *cue_id;
char* cue_settings;
char* cue_id;
// Standard block data
size_t text_size;
char *block_text;
char* block_text;
} vtt_block_t;

// VTT files are a collection of REGION, STYLE and CUE blocks.
Expand Down Expand Up @@ -133,7 +133,7 @@ int vtt_cue_to_caption_frame(vtt_block_t* cue, caption_frame_t* frame);
/*! \brief
\param
*/
vtt_block_t* vtt_cue_from_caption_frame(caption_frame_t* frame, vtt_t *vtt);
vtt_block_t* vtt_cue_from_caption_frame(caption_frame_t* frame, vtt_t* vtt);
/*! \brief
\param
*/
Expand Down
Loading

0 comments on commit e5f8a74

Please sign in to comment.