Skip to content

Commit c58d549

Browse files
committed
Stripped out HLS parsing from a separate library and cleaned it up so that it's an independant library
0 parents  commit c58d549

20 files changed

+4623
-0
lines changed

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2015 Joel Freeman
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
CC = gcc
3+
ODIR = bin
4+
CCDIR = coverage
5+
ONAME = libhlsparse
6+
INSTALL_DIR = /usr/local
7+
CCOBJDIR = $(CCDIR)/obj
8+
CFLAGS = -Ibin -Lbin
9+
LIBS = -lhlsparse
10+
11+
.SECONDEXPANSION:
12+
OBJ_SRC := $(patsubst %.c, %.o, $(wildcard src/*.c))
13+
14+
DEBUG ?= 0
15+
COVERAGE ?= 0
16+
PROFILING ?= 0
17+
18+
ifeq ($(COVERAGE), 1)
19+
CFLAGS += -fprofile-arcs -ftest-coverage -fprofile-dir=$(CCOBJDIR)
20+
DEBUG = 1
21+
endif
22+
23+
ifeq ($(PROFILING), 1)
24+
CFLAGS += -pg
25+
DEBUG = 1
26+
endif
27+
28+
ifeq ($(DEBUG), 1)
29+
CFLAGS += -O0 -g
30+
else
31+
CFLAGS += -O2
32+
endif
33+
34+
all: static tests
35+
36+
.PHONY: style static tests check clean
37+
38+
static: $(OBJ_SRC)
39+
mkdir -p $(ODIR)
40+
ar rcs $(ODIR)/$(ONAME).a $(OBJ_SRC)
41+
cp src/hlsparse*.h $(ODIR)/
42+
43+
%.o: %.c
44+
$(CC) -c -o $@ $< $(CFLAGS)
45+
46+
install: static
47+
mkdir -p $(INSTALL_DIR)/include/$(ONAME)
48+
mkdir -p $(INSTALL_DIR)/lib
49+
cp $(ODIR)/*.h $(INSTALL_DIR)/include/$(ONAME)/
50+
cp $(ODIR)/$(ONAME).a $(INSTALL_DIR)/lib/
51+
52+
remove:
53+
rm -f $(INSTALL_DIR)/include/$(ONAME)/*.h
54+
rm -r -f $(INSTALL_DIR)/include/$(ONAME)
55+
rm -f $(INSTALL_DIR)/lib/$(ONAME).a
56+
57+
tests: static
58+
$(MAKE) -C test/
59+
60+
examples: static
61+
$(MAKE) -C examples/
62+
63+
check: static
64+
$(MAKE) -C test/ check
65+
66+
clean:
67+
$(MAKE) -C test clean
68+
rm -f -r $(ODIR) $(CCDIR)
69+
find . -type f -name '*.o' -exec rm {} \;
70+
find . -type f -name '*.o.dSYM' -exec rm {} \;
71+
find . -type f -name '*.o.gcno' -exec rm {} \;
72+
find . -type f -name '*.o.gcda' -exec rm {} \;
73+
find . -type f -name 'gmon.out' -exec rm {} \;

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# HLS Parse
2+
Library for parsing an HLS master and media playlist into a C object structure.
3+
4+
## Building
5+
Run `make static` to build a static library. See the generated `bin` directory.
6+
Run `make check` to build and run the tests.
7+
8+
## Example
9+
For a more thorough example see `examples/example.c` in the source code.
10+
```
11+
// Global initialization of the library.
12+
HLSCode res = hlsparse_global_init();
13+
14+
// create a master playlist structure.
15+
master_t myMaster;
16+
res = hlsparse_master_init(&myMaster);
17+
18+
// parse some playlist data into our master structure.
19+
masterSrc = /* char * utf8 master playlist string */
20+
int read = hlsparse_master(masterSrc, strlen(masterSrc), &myMaster);
21+
```

examples/Makefile

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
CC = gcc
2+
CCDIR = coverage
3+
CCOBJDIR = $(CCDIR)/obj
4+
CFLAGS = -I../bin -L../bin
5+
LIBS = -lhlsparse
6+
7+
.SECONDEXPANSION:
8+
OBJ_SRC := $(patsubst %.c, %.o, $(wildcard *.c))
9+
10+
DEBUG ?= 0
11+
COVERAGE ?= 0
12+
PROFILING ?= 0
13+
14+
ifeq ($(COVERAGE), 1)
15+
CFLAGS += -fprofile-arcs -ftest-coverage -fprofile-dir=$(CCOBJDIR)
16+
DEBUG = 1
17+
endif
18+
19+
ifeq ($(PROFILING), 1)
20+
CFLAGS += -pg
21+
DEBUG = 1
22+
endif
23+
24+
ifeq ($(DEBUG), 1)
25+
CFLAGS += -O0 -g
26+
else
27+
CFLAGS += -O2
28+
endif
29+
30+
all: $(OBJ_SRC)
31+
32+
.PHONY: clean
33+
34+
%.o: %.c
35+
$(CC) -o $@ $< $(CFLAGS) $(LIBS)
36+
37+
clean:
38+
find . -type f -name '*.o' -exec rm {} \;
39+
find . -type f -name '*.o.dSYM' -exec rm {} \;
40+
find . -type f -name '*.o.gcno' -exec rm {} \;
41+
find . -type f -name '*.o.gcda' -exec rm {} \;
42+
find . -type f -name 'gmon.out' -exec rm {} \;

examples/example.c

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <hlsparse.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
5+
const char *masterSrc = "#EXTM3U\n"\
6+
"#EXT-X-VERSION:7\n"\
7+
"#EXT-X-MEDIA:TYPE=VIDEO,URI=\"http://www.test.com\",GROUP-ID=\"groupId\",NAME=\"media\"\n"\
8+
"#EXT-X-STREAM-INF:BANDWIDTH=900000,CODECS=\"mp4a.40.2,avc1.4d401e\",RESOLUTION=1280x720\n"\
9+
"/path/to/stream_inf/900.m3u8\n"\
10+
"#EXT-X-STREAM-INF:BANDWIDTH=1500000,CODECS=\"mp4a.40.2.avc1.4d401e\",RESOLUTION=1920x1080\n"\
11+
"/path/to/stream_inf/1500.m3u8\n"\
12+
"#EXT-X-I-FRAME-STREAM-INF:URI=\"http://www.test.com\",BANDWIDTH=900000\n"\
13+
"#EXT-X-SESSION-DATA:DATA-ID=\"com.example.movie.title\",VALUE=\"value\",URI=\"http://www.test.com/data.json\""\
14+
"#EXT-X-SESSION-KEY:METHOD=AES-128,URI=\"http://www.test.com/key\""\
15+
"#EXT-X-INDEPENDENT-SEGMENTS\n"\
16+
"#EXT-X-START:TIME-OFFSET=10.0,PRECISE=YES\n";
17+
18+
int main() {
19+
// Initialize the library
20+
HLSCode res = hlsparse_global_init();
21+
if(res != HLS_OK) {
22+
fprintf(stderr, "failed to initialize hlsparse");
23+
return -1;
24+
}
25+
26+
// create a master playlist structure
27+
master_t myMaster;
28+
res = hlsparse_master_init(&myMaster);
29+
if(res != HLS_OK) {
30+
fprintf(stderr, "failed to initialize master playlist structure");
31+
return -1;
32+
}
33+
34+
// parse the playlist information into our master structure
35+
int read = hlsparse_master(masterSrc, strlen(masterSrc), &myMaster);
36+
printf("read a total of %d bytes parsing the master playlist source\n", read);
37+
38+
// print out all the StreamInf bitrates that were found
39+
stream_inf_list_t *streamInf = &myMaster.stream_infs;
40+
int count = 0;
41+
while(streamInf) {
42+
printf("StreamInf %d Bandwidth: %f\n", count, streamInf->data->bandwidth);
43+
++count;
44+
streamInf = streamInf->next;
45+
}
46+
47+
return 0;
48+
}

src/hlsparse.c

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#include "parse.h"
2+
#include <memory.h>
3+
4+
hlsparse_malloc_callback hls_malloc = (hlsparse_malloc_callback) malloc;
5+
hlsparse_free_callback hls_free = (hlsparse_free_callback) free;
6+
7+
HLSCode hlsparse_global_init(void)
8+
{
9+
hls_malloc = (hlsparse_malloc_callback) malloc;
10+
hls_free = (hlsparse_free_callback) free;
11+
12+
return HLS_OK;
13+
}
14+
15+
HLSCode hlsparse_init_mem(hlsparse_malloc_callback m, hlsparse_free_callback f)
16+
{
17+
if(!m || !f) {
18+
return HLS_ERROR;
19+
}
20+
21+
hls_malloc = m;
22+
hls_free = f;
23+
return HLS_OK;
24+
}
25+
26+
HLSCode hlsparse_master_init(master_t *dest)
27+
{
28+
if(!dest) {
29+
return HLS_ERROR;
30+
}
31+
32+
memset(dest, 0, sizeof(master_t));
33+
return HLS_OK;
34+
}
35+
36+
HLSCode hlsparse_media_playlist_init(media_playlist_t *dest)
37+
{
38+
if(!dest) {
39+
return HLS_ERROR;
40+
}
41+
42+
memset(dest, 0, sizeof(media_playlist_t));
43+
return HLS_OK;
44+
}
45+
46+
HLSCode hlsparse_master_term(master_t *dest)
47+
{
48+
if(!dest) {
49+
return HLS_ERROR;
50+
}
51+
52+
char **params[] = {
53+
&dest->uri
54+
};
55+
56+
parse_param_term(params, 1);
57+
parse_string_list_term(&dest->custom_tags);
58+
parse_session_data_list_term(&dest->session_data);
59+
parse_media_list_term(&dest->media);
60+
parse_stream_inf_list_term(&dest->stream_infs);
61+
parse_iframe_stream_inf_list_term(&dest->iframe_stream_infs);
62+
63+
return HLS_OK;
64+
}
65+
66+
HLSCode hlsparse_media_playlist_term(media_playlist_t *dest)
67+
{
68+
if(!dest) {
69+
return HLS_ERROR;
70+
}
71+
char **params[] = {
72+
&dest->uri
73+
};
74+
75+
parse_param_term(params, 1);
76+
parse_string_list_term(&dest->custom_tags);
77+
parse_segment_list_term(&dest->segments);
78+
79+
return HLS_OK;
80+
}
81+
82+
int hlsparse_master(const char *src, size_t size, master_t *dest)
83+
{
84+
int res = 0;
85+
86+
// make sure we have some data
87+
if (src && *src != '\0' && src < &src[size]) {
88+
// go through each line parsing the tags
89+
const char *pt = src;
90+
while (*pt != '\0') {
91+
if (*pt == '#') {
92+
++pt;
93+
pt += parse_master_tag(pt, size - (pt - src), dest);
94+
} else {
95+
++pt;
96+
}
97+
}
98+
99+
res = pt - src;
100+
}
101+
102+
return res;
103+
}
104+
105+
int hlsparse_media_playlist(const char *src, size_t size, media_playlist_t *dest)
106+
{
107+
int res = 0;
108+
109+
if(dest) {
110+
// reset the duration
111+
dest->duration = 0;
112+
// reset the segment byte range
113+
dest->next_segment_byterange.n = dest->next_segment_byterange.o = 0;
114+
}
115+
116+
// make sure we have some data
117+
if(src && (src[0] != '\0') && size > 0) {
118+
// go through each line parsing the tags
119+
const char* pt = &src[0];
120+
while(*pt != '\0' && pt < &src[size]) {
121+
if(*pt == '#') {
122+
++pt;
123+
pt += parse_media_playlist_tag(pt, size - (pt - src), dest);
124+
} else {
125+
++pt;
126+
}
127+
}
128+
129+
res = pt - src;
130+
}
131+
132+
return res;
133+
}

0 commit comments

Comments
 (0)