[FFmpeg-devel] [PATCH 2/2] MAINTAINERS: add myself as hls encryption maintainer

2015-06-16 Thread Christian Suloway
Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7b239a1..fa9e966 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -416,6 +416,7 @@ Muxers/Demuxers:
   gxf.c Reimar Doeffinger
   gxfenc.c  Baptiste Coudurier
   hls.c Anssi Hannula
+  hls encryption (hlsenc.c) Christian Suloway
   idcin.c   Mike Melanson
   idroqdec.cMike Melanson
   iff.c Jaikrishnan Menon
-- 
2.4.2

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/2] avformat/hlsenc: removed empty/unused print_encryption_tag function

2015-06-16 Thread Christian Suloway
Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/hlsenc.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 68c6479..cf29f4f 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -310,10 +310,6 @@ static void hls_free_segments(HLSSegment *p)
 }
 }
 
-static void print_encryption_tag(HLSContext *hls, HLSSegment *en)
-{
-}
-
 static int hls_window(AVFormatContext *s, int last)
 {
 HLSContext *hls = s-priv_data;
-- 
2.4.2

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2015-02-11 Thread Christian Suloway
bumping this thread

On 2/3/15, 9:54 AM, Christian Suloway csulo...@globaleagleent.com
wrote:

Updated patch is attached.

On 1/10/15, 3:06 PM, Michael Niedermayer michae...@gmx.at wrote:

i got it working after a few tries but
please provide an example that works and documentation that describes
the feature in a way sufficient to use it without reading the code
ideally add a example to the documentation too

The documentation and commit message have been updated. Let me know if
further clarification is needed.

also the parser is fragile it requires to carefully place newlines
or it will fail, i think the previous strcspn() code was better if it
avoided that, i didnt realize this

I have reverted this section to the previous strcspn() code.

Thanks,
Christian




0001-avformat-hlsenc-added-HLS-encryption.patch
Description: 0001-avformat-hlsenc-added-HLS-encryption.patch
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2015-02-03 Thread Christian Suloway
Updated patch is attached.

On 1/10/15, 3:06 PM, Michael Niedermayer michae...@gmx.at wrote:

i got it working after a few tries but
please provide an example that works and documentation that describes
the feature in a way sufficient to use it without reading the code
ideally add a example to the documentation too

The documentation and commit message have been updated. Let me know if
further clarification is needed.

also the parser is fragile it requires to carefully place newlines
or it will fail, i think the previous strcspn() code was better if it
avoided that, i didnt realize this

I have reverted this section to the previous strcspn() code.

Thanks,
Christian



0001-avformat-hlsenc-added-HLS-encryption.patch
Description: 0001-avformat-hlsenc-added-HLS-encryption.patch
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2015-01-09 Thread Christian Suloway
New version of the patch attached to address your comments.
Thanks,
Christian

On Jan 7, 2015, at 2:17 PM, Michael Niedermayer michae...@gmx.at wrote:

 Please add a testcase/example to either the documentation or
 commit message

Example added to the commit message.

 +ff_get_line(pb, hls-key_uri, sizeof(hls-key_uri));
 +hls-key_uri[strcspn(hls-key_uri, \r\n)] = '\0';
 +
 +ff_get_line(pb, hls-key_file, sizeof(hls-key_file));
 +hls-key_file[strcspn(hls-key_file, \r\n)] = '\0';
 +
 +ff_get_line(pb, hls-iv_string, sizeof(hls-iv_string));
 +hls-iv_string[strcspn(hls-iv_string, \r\n)] = '\0';
 
 in what case are the strcspn() needed ?

Replaced with terminating character check/replace, and combined with error 
check.

 +if (!err)
 +snprintf(iv_string, sizeof(iv_string), %032llx, c-sequence);
 
 libavformat/hlsenc.c:407:13: warning: format ‘%llx’ expects argument of type 
 ‘long long unsigned int’, but argument 4 has type ‘int64_t’ [-Wformat]
 libavformat/hlsenc.c:407:13: warning: format ‘%llx’ expects argument of type 
 ‘long long unsigned int’, but argument 4 has type ‘int64_t’ [-Wformat]

Replaced with PRIx64 macro.

 +filename_size = strlen(prefix) + strlen(oc-filename) + 1;
 +filename = av_malloc(filename_size);
 +if (!filename) {
 +av_dict_free(options);
 +return AVERROR(ENOMEM);
 +}
 +av_strlcpy(filename, prefix, filename_size);
 +av_strlcat(filename, oc-filename, filename_size);
 
 this looks like it can be simplified with av_asprintf()

Replaced with av_asprintf().



0001-avformat-hlsenc-added-HLS-encryption.patch
Description: 0001-avformat-hlsenc-added-HLS-encryption.patch



___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2015-01-09 Thread Christian Suloway
Resending attachment.


From: ffmpeg-devel-boun...@ffmpeg.org ffmpeg-devel-boun...@ffmpeg.org on 
behalf of Christian Suloway csulo...@globaleagleent.com
Sent: Friday, January 9, 2015 5:02 PM
To: FFmpeg development discussions and patches
Subject: Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

New version of the patch attached to address your comments.
Thanks,
Christian

On Jan 7, 2015, at 2:17 PM, Michael Niedermayer michae...@gmx.at wrote:

 Please add a testcase/example to either the documentation or
 commit message

Example added to the commit message.

 +ff_get_line(pb, hls-key_uri, sizeof(hls-key_uri));
 +hls-key_uri[strcspn(hls-key_uri, \r\n)] = '\0';
 +
 +ff_get_line(pb, hls-key_file, sizeof(hls-key_file));
 +hls-key_file[strcspn(hls-key_file, \r\n)] = '\0';
 +
 +ff_get_line(pb, hls-iv_string, sizeof(hls-iv_string));
 +hls-iv_string[strcspn(hls-iv_string, \r\n)] = '\0';

 in what case are the strcspn() needed ?

Replaced with terminating character check/replace, and combined with error 
check.

 +if (!err)
 +snprintf(iv_string, sizeof(iv_string), %032llx, c-sequence);

 libavformat/hlsenc.c:407:13: warning: format ‘%llx’ expects argument of type 
 ‘long long unsigned int’, but argument 4 has type ‘int64_t’ [-Wformat]
 libavformat/hlsenc.c:407:13: warning: format ‘%llx’ expects argument of type 
 ‘long long unsigned int’, but argument 4 has type ‘int64_t’ [-Wformat]

Replaced with PRIx64 macro.

 +filename_size = strlen(prefix) + strlen(oc-filename) + 1;
 +filename = av_malloc(filename_size);
 +if (!filename) {
 +av_dict_free(options);
 +return AVERROR(ENOMEM);
 +}
 +av_strlcpy(filename, prefix, filename_size);
 +av_strlcat(filename, oc-filename, filename_size);

 this looks like it can be simplified with av_asprintf()

Replaced with av_asprintf().



0001-avformat-hlsenc-added-HLS-encryption.patch
Description: 0001-avformat-hlsenc-added-HLS-encryption.patch
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2015-01-07 Thread Christian Suloway
Added HLS encryption with -hls_key_info_file key_info_file option. The
first line of key_info_file specifies the key URI for the playlist. The
second line specifies the path to the file containing the encryption
key. An optional third line specifies an IV to use instead of the
segment number. Changes to key_info_file will be reflected in segment
encryption along with an entry in the playlist for the new key URI and
IV.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |   9 
 libavformat/hlsenc.c | 130 +--
 2 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index a1264d2..f2ecf8b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -263,6 +263,15 @@ ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
 This example will produce the playlist, @file{out.m3u8}, and segment files:
 @file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
 
+@item hls_key_info_file @var{file}
+Use in the information in @var{file} for segment encryption. The first line of
+@var{file} specifies the key URI for the playlist. The second line specifies
+the path to the file containing the encryption key as a single packed array of
+16 octets in binary format. The optional third line specifies a hexidecimal
+string for the initialization vector (IV) to be used instead of the segment
+number. Changes to @var{file} will result in segment encryption with the new
+key/IV and an entry in the playlist for the new key URI/IV.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index f46e8d4..7f2bc96 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -37,12 +37,18 @@
 #include internal.h
 #include os_support.h
 
+#define BLOCKSIZE 16
+#define LINE_BUFFER_SIZE 1024
+
 typedef struct HLSSegment {
 char filename[1024];
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char key_uri[LINE_BUFFER_SIZE + 1];
+char iv_string[BLOCKSIZE*2 + 1];
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -86,6 +92,12 @@ typedef struct HLSContext {
 char *format_options_str;
 AVDictionary *format_options;
 
+char *key_info_file;
+char key_file[LINE_BUFFER_SIZE + 1];
+char key_uri[LINE_BUFFER_SIZE + 1];
+char key_string[BLOCKSIZE*2 + 1];
+char iv_string[BLOCKSIZE*2 + 1];
+
 AVIOContext *pb;
 } HLSContext;
 
@@ -154,6 +166,62 @@ fail:
 return ret;
 }
 
+static int hls_encryption_start(AVFormatContext *s)
+{
+HLSContext *hls = s-priv_data;
+int ret;
+AVIOContext *pb;
+uint8_t key[BLOCKSIZE];
+
+if ((ret = avio_open2(pb, hls-key_info_file, AVIO_FLAG_READ,
+   s-interrupt_callback, NULL))  0) {
+av_log(hls, AV_LOG_ERROR,
+error opening key info file %s\n, hls-key_info_file);
+return ret;
+}
+
+ff_get_line(pb, hls-key_uri, sizeof(hls-key_uri));
+hls-key_uri[strcspn(hls-key_uri, \r\n)] = '\0';
+
+ff_get_line(pb, hls-key_file, sizeof(hls-key_file));
+hls-key_file[strcspn(hls-key_file, \r\n)] = '\0';
+
+ff_get_line(pb, hls-iv_string, sizeof(hls-iv_string));
+hls-iv_string[strcspn(hls-iv_string, \r\n)] = '\0';
+
+avio_close(pb);
+
+if (!*hls-key_uri) {
+av_log(hls, AV_LOG_ERROR, no key URI specified in key info file\n);
+return AVERROR(EINVAL);
+}
+av_log(hls, AV_LOG_DEBUG, key URI = %s\n, hls-key_uri);
+
+if (!*hls-key_file) {
+av_log(hls, AV_LOG_ERROR, no key file specified in key info file\n);
+return AVERROR(EINVAL);
+}
+av_log(hls, AV_LOG_DEBUG, key file = %s\n, hls-key_file);
+
+if ((ret = avio_open2(pb, hls-key_file, AVIO_FLAG_READ,
+   s-interrupt_callback, NULL))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key file %s\n, 
hls-key_file);
+return ret;
+}
+
+ret = avio_read(pb, key, sizeof(key));
+avio_close(pb);
+if (ret != sizeof(key)) {
+av_log(hls, AV_LOG_ERROR, error reading key file %s\n, 
hls-key_file);
+if (ret = 0 || ret == AVERROR_EOF)
+ret = AVERROR(EINVAL);
+return ret;
+}
+ff_data_to_hex(hls-key_string, key, sizeof(key), 0);
+
+return 0;
+}
+
 static int hls_mux_init(AVFormatContext *s)
 {
 HLSContext *hls = s-priv_data;
@@ -200,6 +268,11 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 en-size = size;
 en-next = NULL;
 
+if (hls-key_info_file) {
+av_strlcpy(en-key_uri, hls-key_uri, sizeof(en-key_uri));
+av_strlcpy(en-iv_string, hls-iv_string, sizeof(en-iv_string));
+}
+
 if (!hls-segments)
 hls-segments = en;
 else
@@ -237,6 +310,14 @@ static void hls_free_segments

[FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2014-12-30 Thread Christian Suloway
Added HLS encryption with -hls_key_info_file key_info_file option. The
first line of key_info_file specifies the key URI for the playlist. The
second line specifies the path to the file containing the encryption
key. An optional third line specifies an IV to use instead of the
segment number. Changes to key_info_file will be reflected in segment
encryption along with an entry in the playlist for the new key URI and
IV.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |   9 
 libavformat/hlsenc.c | 130 +--
 2 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index a1264d2..f2ecf8b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -263,6 +263,15 @@ ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
 This example will produce the playlist, @file{out.m3u8}, and segment files:
 @file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
 
+@item hls_key_info_file @var{file}
+Use in the information in @var{file} for segment encryption. The first line of
+@var{file} specifies the key URI for the playlist. The second line specifies
+the path to the file containing the encryption key as a single packed array of
+16 octets in binary format. The optional third line specifies a hexidecimal
+string for the initialization vector (IV) to be used instead of the segment
+number. Changes to @var{file} will result in segment encryption with the new
+key/IV and an entry in the playlist for the new key URI/IV.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index f46e8d4..7f2bc96 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -37,12 +37,18 @@
 #include internal.h
 #include os_support.h
 
+#define BLOCKSIZE 16
+#define LINE_BUFFER_SIZE 1024
+
 typedef struct HLSSegment {
 char filename[1024];
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char key_uri[LINE_BUFFER_SIZE + 1];
+char iv_string[BLOCKSIZE*2 + 1];
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -86,6 +92,12 @@ typedef struct HLSContext {
 char *format_options_str;
 AVDictionary *format_options;
 
+char *key_info_file;
+char key_file[LINE_BUFFER_SIZE + 1];
+char key_uri[LINE_BUFFER_SIZE + 1];
+char key_string[BLOCKSIZE*2 + 1];
+char iv_string[BLOCKSIZE*2 + 1];
+
 AVIOContext *pb;
 } HLSContext;
 
@@ -154,6 +166,62 @@ fail:
 return ret;
 }
 
+static int hls_encryption_start(AVFormatContext *s)
+{
+HLSContext *hls = s-priv_data;
+int ret;
+AVIOContext *pb;
+uint8_t key[BLOCKSIZE];
+
+if ((ret = avio_open2(pb, hls-key_info_file, AVIO_FLAG_READ,
+   s-interrupt_callback, NULL))  0) {
+av_log(hls, AV_LOG_ERROR,
+error opening key info file %s\n, hls-key_info_file);
+return ret;
+}
+
+ff_get_line(pb, hls-key_uri, sizeof(hls-key_uri));
+hls-key_uri[strcspn(hls-key_uri, \r\n)] = '\0';
+
+ff_get_line(pb, hls-key_file, sizeof(hls-key_file));
+hls-key_file[strcspn(hls-key_file, \r\n)] = '\0';
+
+ff_get_line(pb, hls-iv_string, sizeof(hls-iv_string));
+hls-iv_string[strcspn(hls-iv_string, \r\n)] = '\0';
+
+avio_close(pb);
+
+if (!*hls-key_uri) {
+av_log(hls, AV_LOG_ERROR, no key URI specified in key info file\n);
+return AVERROR(EINVAL);
+}
+av_log(hls, AV_LOG_DEBUG, key URI = %s\n, hls-key_uri);
+
+if (!*hls-key_file) {
+av_log(hls, AV_LOG_ERROR, no key file specified in key info file\n);
+return AVERROR(EINVAL);
+}
+av_log(hls, AV_LOG_DEBUG, key file = %s\n, hls-key_file);
+
+if ((ret = avio_open2(pb, hls-key_file, AVIO_FLAG_READ,
+   s-interrupt_callback, NULL))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key file %s\n, 
hls-key_file);
+return ret;
+}
+
+ret = avio_read(pb, key, sizeof(key));
+avio_close(pb);
+if (ret != sizeof(key)) {
+av_log(hls, AV_LOG_ERROR, error reading key file %s\n, 
hls-key_file);
+if (ret = 0 || ret == AVERROR_EOF)
+ret = AVERROR(EINVAL);
+return ret;
+}
+ff_data_to_hex(hls-key_string, key, sizeof(key), 0);
+
+return 0;
+}
+
 static int hls_mux_init(AVFormatContext *s)
 {
 HLSContext *hls = s-priv_data;
@@ -200,6 +268,11 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 en-size = size;
 en-next = NULL;
 
+if (hls-key_info_file) {
+av_strlcpy(en-key_uri, hls-key_uri, sizeof(en-key_uri));
+av_strlcpy(en-iv_string, hls-iv_string, sizeof(en-iv_string));
+}
+
 if (!hls-segments)
 hls-segments = en;
 else
@@ -237,6 +310,14 @@ static void hls_free_segments

Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2014-12-23 Thread Christian Suloway
On Dec 22, 2014, at 6:36 PM, Michael Niedermayer michae...@gmx.at wrote:
 this looks a bit odd,
 see ff_get_line(), it probably allows to simplify this a lot

Resubmitting using ff_get_line().
Thanks,
Christian

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2014-12-23 Thread Christian Suloway
Added HLS encryption with -hls_key_info_file key_info_file option. The
first line of key_info_file specifies the key URI for the playlist. The
second line specifies the path to the file containing the encryption
key. An optional third line specifies an IV to use instead of the
segment number. Changes to key_info_file will be reflected in segment
encryption along with an entry in the playlist for the new key URI and
IV.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |   9 ++
 libavformat/hlsenc.c | 242 +--
 2 files changed, 245 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index a1264d2..f2ecf8b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -263,6 +263,15 @@ ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
 This example will produce the playlist, @file{out.m3u8}, and segment files:
 @file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
 
+@item hls_key_info_file @var{file}
+Use in the information in @var{file} for segment encryption. The first line of
+@var{file} specifies the key URI for the playlist. The second line specifies
+the path to the file containing the encryption key as a single packed array of
+16 octets in binary format. The optional third line specifies a hexidecimal
+string for the initialization vector (IV) to be used instead of the segment
+number. Changes to @var{file} will result in segment encryption with the new
+key/IV and an entry in the playlist for the new key URI/IV.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index f46e8d4..6969187 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -37,12 +37,19 @@
 #include internal.h
 #include os_support.h
 
+#define BLOCKSIZE 16
+#define LINE_BUFFER_SIZE 1024
+
 typedef struct HLSSegment {
 char filename[1024];
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char *key_uri;
+char *iv_string;
+int attribute_iv;
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -86,9 +93,23 @@ typedef struct HLSContext {
 char *format_options_str;
 AVDictionary *format_options;
 
+char *key_info_file;
+char *key_file;
+char *key_uri;
+char *key_string;
+char *iv_string;
+int attribute_iv;
+
 AVIOContext *pb;
 } HLSContext;
 
+static void hls_free_segment(HLSSegment *en)
+{
+   av_freep(en-key_uri);
+   av_freep(en-iv_string);
+   av_freep(en);
+}
+
 static int hls_delete_old_segments(HLSContext *hls) {
 
 HLSSegment *segment, *previous_segment = NULL;
@@ -145,7 +166,7 @@ static int hls_delete_old_segments(HLSContext *hls) {
 av_free(path);
 previous_segment = segment;
 segment = previous_segment-next;
-av_free(previous_segment);
+hls_free_segment(previous_segment);
 }
 
 fail:
@@ -154,6 +175,140 @@ fail:
 return ret;
 }
 
+static int hls_get_line(AVIOContext *pb, char *buf, int buf_size) {
+int i = 0;
+
+if (!(i = ff_get_line(pb, buf, buf_size)))
+return 0;
+i = strcspn(buf, \r\n);
+if (!i || buf[i] == '\0')
+return AVERROR(EINVAL);
+buf[i] = '\0';
+return i + 1;
+}
+
+static int hls_encryption_start(AVFormatContext *s)
+{
+HLSContext *hls = s-priv_data;
+int ret = 0, i;
+AVIOContext *pb = NULL;
+uint8_t *key = NULL, *iv = NULL;
+char buf[LINE_BUFFER_SIZE + 1], *key_string = NULL, *iv_string = NULL;
+
+if ((ret = avio_open2(pb, hls-key_info_file, AVIO_FLAG_READ,
+   s-interrupt_callback, NULL))  0) {
+av_log(hls, AV_LOG_ERROR,
+error opening key info file %s\n, hls-key_info_file);
+goto fail;
+}
+
+if ((ret = hls_get_line(pb, buf, sizeof(buf))) = 0) {
+if (!ret) {
+av_log(hls, AV_LOG_ERROR, no key URI in key info file\n);
+ret = AVERROR(EINVAL);
+} else
+av_log(hls, AV_LOG_ERROR, malformed key URI in key info file\n);
+goto fail;
+}
+av_free(hls-key_uri);
+hls-key_uri = av_strdup(buf);
+if (!hls-key_uri)
+return AVERROR(ENOMEM);
+av_log(hls, AV_LOG_DEBUG, key URI = %s\n, hls-key_uri);
+
+if ((ret = hls_get_line(pb, buf, sizeof(buf))) = 0) {
+if (!ret) {
+av_log(hls, AV_LOG_ERROR, no key file in key info file\n);
+ret = AVERROR(EINVAL);
+} else
+av_log(hls, AV_LOG_ERROR, malformed key file in key info file\n);
+goto fail;
+}
+av_free(hls-key_file);
+hls-key_file = av_strdup(buf);
+if (!hls-key_file)
+return AVERROR(ENOMEM);
+av_log(hls, AV_LOG_DEBUG, key file = %s\n, hls-key_file);
+
+if ((ret = hls_get_line(pb, buf, sizeof(buf)))  0) {
+av_log(hls, AV_LOG_ERROR

[FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2014-12-22 Thread Christian Suloway
Added HLS encryption with -hls_key_info_file key_info_file option.
The first line of key_info_file specifies the key URI for the playlist.
The second line specifies the path to the file containing the encryption
key. An optional third line specifies an IV to use instead of the
segment number. Changes to key_info_file will be reflected in segment
encryption along with an entry in the playlist for the new key URI and
IV.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |   9 ++
 libavformat/hlsenc.c | 235 +--
 2 files changed, 238 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index a1264d2..f2ecf8b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -263,6 +263,15 @@ ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
 This example will produce the playlist, @file{out.m3u8}, and segment files:
 @file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
 
+@item hls_key_info_file @var{file}
+Use in the information in @var{file} for segment encryption. The first line of
+@var{file} specifies the key URI for the playlist. The second line specifies
+the path to the file containing the encryption key as a single packed array of
+16 octets in binary format. The optional third line specifies a hexidecimal
+string for the initialization vector (IV) to be used instead of the segment
+number. Changes to @var{file} will result in segment encryption with the new
+key/IV and an entry in the playlist for the new key URI/IV.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index f46e8d4..1dba60c 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -37,12 +37,18 @@
 #include internal.h
 #include os_support.h
 
+#define BLOCKSIZE 16
+
 typedef struct HLSSegment {
 char filename[1024];
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char *key_uri;
+char *iv_string;
+int attribute_iv;
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -86,9 +92,23 @@ typedef struct HLSContext {
 char *format_options_str;
 AVDictionary *format_options;
 
+char *key_info_file;
+char *key_file;
+char *key_uri;
+char *key_string;
+char *iv_string;
+int attribute_iv;
+
 AVIOContext *pb;
 } HLSContext;
 
+static void hls_free_segment(HLSSegment *en)
+{
+   av_freep(en-key_uri);
+   av_freep(en-iv_string);
+   av_freep(en);
+}
+
 static int hls_delete_old_segments(HLSContext *hls) {
 
 HLSSegment *segment, *previous_segment = NULL;
@@ -145,7 +165,7 @@ static int hls_delete_old_segments(HLSContext *hls) {
 av_free(path);
 previous_segment = segment;
 segment = previous_segment-next;
-av_free(previous_segment);
+hls_free_segment(previous_segment);
 }
 
 fail:
@@ -154,6 +174,134 @@ fail:
 return ret;
 }
 
+static int hls_encryption_start(HLSContext *hls)
+{
+
+int ret = 0, i;
+AVIOContext *pb = NULL, *dyn_buf = NULL;
+uint8_t buf[1024], *tmp = NULL, *key = NULL, *iv = NULL;
+char *p, *tstr, *saveptr = NULL, *key_string = NULL, *iv_string = NULL;
+
+if ((ret = avio_open(pb, hls-key_info_file, AVIO_FLAG_READ))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key info file %s\n,
+  hls-key_info_file);
+goto fail;
+}
+
+ret = avio_open_dyn_buf(dyn_buf);
+if (ret  0) {
+avio_closep(pb);
+goto fail;
+}
+
+while ((ret = avio_read(pb, buf, sizeof(buf)))  0)
+avio_write(dyn_buf, buf, ret);
+avio_closep(pb);
+if (ret != AVERROR_EOF  ret  0) {
+avio_close_dyn_buf(dyn_buf, tmp);
+goto fail;
+}
+
+avio_w8(dyn_buf, 0);
+if ((ret = avio_close_dyn_buf(dyn_buf, tmp))  0)
+goto fail;
+
+p = tmp;
+if (!(tstr = av_strtok(p, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key URI specified in key info file %s\n,
+  hls-key_info_file);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+av_free(hls-key_uri);
+hls-key_uri = av_strdup(tstr);
+if (!hls-key_uri) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
+if (!(tstr = av_strtok(NULL, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key file specified in key info file 
%s\n,
+  hls-key_info_file);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+av_free(hls-key_file);
+hls-key_file = av_strdup(tstr);
+if (!hls-key_file) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
+if (tstr = av_strtok(NULL, \n, saveptr)) {
+if (ff_hex_to_data(NULL, tstr) != BLOCKSIZE) {
+av_log(hls, AV_LOG_ERROR, invalid length for IV\n

Re: [FFmpeg-devel] [PATCH 1/2] avformat/hlsenc: fix hls_write_trailer() on hls_start() failure

2014-12-16 Thread Christian Suloway
On 12/16/14, 3:23 AM, Carl Eugen Hoyos ceho...@ag.or.at wrote:

Christian Suloway csuloway at row44.com writes:

 Close segment I/O context and append segment in
 hls_write_trailer() only when segment I/O context
 is allocated.

Was this a regression since 25ccf5df?
(And should be backported to 2.5?)

This does not appear specific to 25ccf5df and goes back to 2.2. Also, the
patch does not cover the mpegtsenc context accessing the null I/O context
from hls_write_trailer or hls_write_packet. I don¹t know if this should be
covered in hlsenc or mpegtsenc.

Examples:

   177  void avio_write(AVIOContext *s, const unsigned char *buf, int size)
   178  {
- 179  if (s-direct  !s-update_checksum) {
   180  avio_flush(s);
   181  writeout(s, buf, size);
   182  return;

* thread #1: tid = 0x1548b77, 0x0001002879f7
libavformat.56.dylib`avio_write(s=0x,
buf=0x7fff5fbff690, size=188) + 23 at aviobuf.c:179, queue =
'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1,
address=0xa0)
  * frame #0: 0x0001002879f7
libavformat.56.dylib`avio_write(s=0x,
buf=0x7fff5fbff690, size=188) + 23 at aviobuf.c:179
frame #1: 0x00010034542b
libavformat.56.dylib`mpegts_write_pes(s=0x000103032200,
st=0x0001021026f0, payload=0x00010303c0a8, payload_size=1256,
pts=1341180, dts=1341180, key=1) + 4347 at mpegtsenc.c:1187
frame #2: 0x000100344303
libavformat.56.dylib`mpegts_write_flush(s=0x000103032200) + 147 at
mpegtsenc.c:1379
frame #3: 0x000100344161
libavformat.56.dylib`mpegts_write_end(s=0x000103032200) + 33 at
mpegtsenc.c:1403
frame #4: 0x00010034d834
libavformat.56.dylib`av_write_trailer(s=0x000103032200) + 276 at
mux.c:949
frame #5: 0x0001002cdf1d
libavformat.56.dylib`hls_write_trailer(s=0x000103030400) + 45 at
hlsenc.c:476
frame #6: 0x00010034d834
libavformat.56.dylib`av_write_trailer(s=0x000103030400) + 276 at
mux.c:949
frame #7: 0x00010001bdb8 ffmpeg`transcode + 568 at ffmpeg.c:3799
frame #8: 0x00010001b3df ffmpeg`main(argc=11,
argv=0x7fff5fbffa28) + 447 at ffmpeg.c:3946

or

* thread #1: tid = 0x1564f17, 0x0001002879f7
libavformat.56.dylib`avio_write(s=0x,
buf=0x7fff5fbff3c0, size=188) + 23 at aviobuf.c:179, queue =
'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1,
address=0xa0)
  * frame #0: 0x0001002879f7
libavformat.56.dylib`avio_write(s=0x,
buf=0x7fff5fbff3c0, size=188) + 23 at aviobuf.c:179
frame #1: 0x00010034542b
libavformat.56.dylib`mpegts_write_pes(s=0x00010365f600,
st=0x00010210d6d0, payload=0x0001036694a8, payload_size=2619,
pts=396540, dts=396540, key=1) + 4347 at mpegtsenc.c:1187
frame #2: 0x0001003482c4
libavformat.56.dylib`mpegts_write_packet_internal(s=0x00010365f600,
pkt=0x7fff5fbff718) + 2068 at mpegtsenc.c:1341
frame #3: 0x000100344130
libavformat.56.dylib`mpegts_write_packet(s=0x00010365f600,
pkt=0x7fff5fbff718) + 64 at mpegtsenc.c:1393
frame #4: 0x00010034c6ef
libavformat.56.dylib`write_packet(s=0x00010365f600,
pkt=0x7fff5fbff718) + 975 at mux.c:598
frame #5: 0x00010034b7f5
libavformat.56.dylib`av_write_frame(s=0x00010365f600,
pkt=0x7fff5fbff718) + 421 at mux.c:654
frame #6: 0x00010034db6a
libavformat.56.dylib`ff_write_chained(dst=0x00010365f600,
dst_stream=1, pkt=0x7fff5fbff900, src=0x000103030400,
interleave=0) + 394 at mux.c:999
frame #7: 0x0001002cded1
libavformat.56.dylib`hls_write_packet(s=0x000103030400,
pkt=0x7fff5fbff900) + 929 at hlsenc.c:466
frame #8: 0x00010034c6ef
libavformat.56.dylib`write_packet(s=0x000103030400,
pkt=0x7fff5fbff900) + 975 at mux.c:598
frame #9: 0x00010034d77f
libavformat.56.dylib`av_write_trailer(s=0x000103030400) + 95 at
mux.c:934
frame #10: 0x00010001bdb8 ffmpeg`transcode + 568 at ffmpeg.c:3799
frame #11: 0x00010001b3df ffmpeg`main(argc=11,
argv=0x7fff5fbffa30) + 447 at ffmpeg.c:3946

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2014-12-15 Thread Christian Suloway
On 12/12/14, 9:57 PM, Michael Niedermayer michae...@gmx.at wrote:
combining the random seed with a LFG seems a bit odd
i would out of principle use something stronger, though i dont know
what the exact scenarios are this is intended to prevent, so maybe
its fine

Yes, this is a good point. I will resubmit the patch with the IV
optionally specified as part of the ³key_info_file² and leave IV
generation outside of ffmpeg. Let me know you would like this done
differently.
Thanks,
Christian

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] avformat/hlsenc: added HLS encryption

2014-12-15 Thread Christian Suloway
Added HLS encryption with -hls_key_info_file key_info_file option. The
first line of key_info_file specifies the key URI for the playlist. The
second line specifies the path to the file containing the encryption
key. An optional third line specifies an IV to use instead of the
segment number. Changes to key_info_file will be reflected in segment
encryption along with an entry in the playlist for the new key URI and
IV.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |   9 ++
 libavformat/hlsenc.c | 235 +--
 2 files changed, 238 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index a1264d2..f2ecf8b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -263,6 +263,15 @@ ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
 This example will produce the playlist, @file{out.m3u8}, and segment files:
 @file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
 
+@item hls_key_info_file @var{file}
+Use in the information in @var{file} for segment encryption. The first line of
+@var{file} specifies the key URI for the playlist. The second line specifies
+the path to the file containing the encryption key as a single packed array of
+16 octets in binary format. The optional third line specifies a hexidecimal
+string for the initialization vector (IV) to be used instead of the segment
+number. Changes to @var{file} will result in segment encryption with the new
+key/IV and an entry in the playlist for the new key URI/IV.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 7645065..f62675e 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -37,12 +37,18 @@
 #include internal.h
 #include os_support.h
 
+#define BLOCKSIZE 16
+
 typedef struct HLSSegment {
 char filename[1024];
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char *key_uri;
+char *iv_string;
+int attribute_iv;
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -86,9 +92,23 @@ typedef struct HLSContext {
 char *format_options_str;
 AVDictionary *format_options;
 
+char *key_info_file;
+char *key_file;
+char *key_uri;
+char *key_string;
+char *iv_string;
+int attribute_iv;
+
 AVIOContext *pb;
 } HLSContext;
 
+static void hls_free_segment(HLSSegment *en)
+{
+   av_freep(en-key_uri);
+   av_freep(en-iv_string);
+   av_freep(en);
+}
+
 static int hls_delete_old_segments(HLSContext *hls) {
 
 HLSSegment *segment, *previous_segment = NULL;
@@ -145,7 +165,7 @@ static int hls_delete_old_segments(HLSContext *hls) {
 av_free(path);
 previous_segment = segment;
 segment = previous_segment-next;
-av_free(previous_segment);
+hls_free_segment(previous_segment);
 }
 
 fail:
@@ -154,6 +174,134 @@ fail:
 return ret;
 }
 
+static int hls_encryption_start(HLSContext *hls)
+{
+
+int ret = 0, i;
+AVIOContext *pb = NULL, *dyn_buf = NULL;
+uint8_t buf[1024], *tmp = NULL, *key = NULL, *iv = NULL;
+char *p, *tstr, *saveptr = NULL, *key_string = NULL, *iv_string = NULL;
+
+if ((ret = avio_open(pb, hls-key_info_file, AVIO_FLAG_READ))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key info file %s\n,
+  hls-key_info_file);
+goto fail;
+}
+
+ret = avio_open_dyn_buf(dyn_buf);
+if (ret  0) {
+avio_closep(pb);
+goto fail;
+}
+
+while ((ret = avio_read(pb, buf, sizeof(buf)))  0)
+avio_write(dyn_buf, buf, ret);
+avio_closep(pb);
+if (ret != AVERROR_EOF  ret  0) {
+avio_close_dyn_buf(dyn_buf, tmp);
+goto fail;
+}
+
+avio_w8(dyn_buf, 0);
+if ((ret = avio_close_dyn_buf(dyn_buf, tmp))  0)
+goto fail;
+
+p = tmp;
+if (!(tstr = av_strtok(p, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key URI specified in key info file %s\n,
+  hls-key_info_file);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+av_free(hls-key_uri);
+hls-key_uri = av_strdup(tstr);
+if (!hls-key_uri) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
+if (!(tstr = av_strtok(NULL, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key file specified in key info file 
%s\n,
+  hls-key_info_file);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+av_free(hls-key_file);
+hls-key_file = av_strdup(tstr);
+if (!hls-key_file) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
+if (tstr = av_strtok(NULL, \n, saveptr)) {
+if (ff_hex_to_data(NULL, tstr) != BLOCKSIZE) {
+av_log(hls, AV_LOG_ERROR, invalid length for IV\n

[FFmpeg-devel] [PATCH 1/2] avformat/hlsenc: fix hls_write_trailer() on hls_start() failure

2014-12-15 Thread Christian Suloway
Close segment I/O context and append segment in hls_write_trailer() only
when segment I/O context is allocated.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/hlsenc.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 79f3a23..7645065 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -449,7 +449,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 av_opt_set(hls-avf-priv_data, mpegts_flags, 
resend_headers, 0);
 hls-number++;
 } else {
-avio_close(oc-pb);
+avio_closep(oc-pb);
 
 ret = hls_start(s);
 }
@@ -474,10 +474,12 @@ static int hls_write_trailer(struct AVFormatContext *s)
 AVFormatContext *oc = hls-avf;
 
 av_write_trailer(oc);
-hls-size = avio_tell(hls-avf-pb) - hls-start_pos;
-avio_closep(oc-pb);
+if (oc-pb) {
+hls-size = avio_tell(hls-avf-pb) - hls-start_pos;
+avio_closep(oc-pb);
+hls_append_segment(hls, hls-duration, hls-start_pos, hls-size);
+}
 av_free(hls-basename);
-hls_append_segment(hls, hls-duration, hls-start_pos, hls-size);
 avformat_free_context(oc);
 hls-avf = NULL;
 hls_window(s, 1);
-- 
1.9.3 (Apple Git-50)

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2014-12-11 Thread Christian Suloway
Added HLS encryption with -hls_key_info_file key_info_file option. The
first line of key_info_file specifies the key URI for the playlist, and
the second line specifies the path to the file containing the encryption
key. Changes to key_info_file will be reflected in segment encryption
along with an entry in the playlist for the new key URI.

Also added -hls_flags random_iv option flag to use a random IV for
encryption instead of the segment number.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |  11 +++
 libavformat/hlsenc.c | 257 +--
 2 files changed, 262 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index a1264d2..29a5de3 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -263,6 +263,13 @@ ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
 This example will produce the playlist, @file{out.m3u8}, and segment files:
 @file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
 
+@item hls_key_info_file @var{file}
+Use in the information in @var{file} for segment encryption. The first line of
+@var{file} specifies the key URI for the playlist. The second line specifies
+the path to the file containing the encryption key as a single packed array of
+16 octets in binary format. Changes to @var{file} will result in segment
+encryption with the new key and an entry in the playlist for the new key URI.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
@@ -277,6 +284,10 @@ Will produce the playlist, @file{out.m3u8}, and a single 
segment file,
 @item hls_flags delete_segments
 Segment files removed from the playlist are deleted after a period of time
 equal to the duration of the segment plus the duration of the playlist.
+
+@item hls_flags random_iv
+Segment file encryption will use a random initialization vector (IV) instead of
+the segment number.
 @end table
 
 @anchor{ico}
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 79f3a23..5bde70e 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -32,17 +32,24 @@
 #include libavutil/avstring.h
 #include libavutil/opt.h
 #include libavutil/log.h
+#include libavutil/lfg.h
+#include libavutil/random_seed.h
 
 #include avformat.h
 #include internal.h
 #include os_support.h
 
+#define BLOCKSIZE 16
+
 typedef struct HLSSegment {
 char filename[1024];
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char *key_uri;
+char *iv_string;
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -50,6 +57,7 @@ typedef enum HLSFlags {
 // Generate a single media file and use byte ranges in the playlist.
 HLS_SINGLE_FILE = (1  0),
 HLS_DELETE_SEGMENTS = (1  1),
+HLS_RANDOM_IV = (1  2),
 } HLSFlags;
 
 typedef struct HLSContext {
@@ -86,9 +94,23 @@ typedef struct HLSContext {
 char *format_options_str;
 AVDictionary *format_options;
 
+char *key_info_file;
+char *key_file;
+char *key_uri;
+char *key_string;
+char *iv_string;
+AVLFG *lfg;
+
 AVIOContext *pb;
 } HLSContext;
 
+static void hls_free_segment(HLSSegment *en)
+{
+   av_freep(en-key_uri);
+   av_freep(en-iv_string);
+   av_freep(en);
+}
+
 static int hls_delete_old_segments(HLSContext *hls) {
 
 HLSSegment *segment, *previous_segment = NULL;
@@ -145,7 +167,7 @@ static int hls_delete_old_segments(HLSContext *hls) {
 av_free(path);
 previous_segment = segment;
 segment = previous_segment-next;
-av_free(previous_segment);
+hls_free_segment(previous_segment);
 }
 
 fail:
@@ -154,6 +176,157 @@ fail:
 return ret;
 }
 
+static int hls_encryption_init(AVFormatContext *s)
+{
+HLSContext *hls = s-priv_data;
+
+if (hls-flags  HLS_RANDOM_IV) {
+hls-lfg = av_malloc(sizeof(AVLFG));
+if (!hls-lfg)
+return AVERROR(ENOMEM);
+av_lfg_init(hls-lfg, av_get_random_seed());
+}
+
+return 0;
+}
+
+static int hls_encryption_start(HLSContext *hls)
+{
+
+int ret = 0, i, j, rotate_iv = 0;
+AVIOContext *pb = NULL;
+AVIOContext *dyn_buf = NULL;
+uint8_t buf[1024], *tmp = NULL, *key = NULL, *iv = NULL;
+char *p, *tstr, *saveptr = NULL, *key_string = NULL;
+unsigned int u;
+
+if ((ret = avio_open(pb, hls-key_info_file, AVIO_FLAG_READ))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key info file %s\n,
+  hls-key_info_file);
+goto fail;
+}
+
+ret = avio_open_dyn_buf(dyn_buf);
+if (ret  0) {
+avio_closep(pb);
+goto fail;
+}
+
+while ((ret = avio_read(pb, buf, sizeof(buf)))  0)
+avio_write(dyn_buf, buf, ret);
+avio_closep(pb);
+if (ret != AVERROR_EOF  ret  0) {
+avio_close_dyn_buf(dyn_buf, tmp);
+goto fail;
+}
+
+avio_w8(dyn_buf

Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added segment file deletion

2014-12-10 Thread Christian Suloway
On 12/9/14, 7:44 PM, Michael Niedermayer michae...@gmx.at wrote:

On Mon, Dec 08, 2014 at 10:25:05AM -0600, Christian Suloway wrote:
 This option flag deletes segment files removed from the playlist after a
 period of time equal to the duration of the segment plus the duration of
 the playlist.

can you explain the usecase for this ?
isnt -hls_wrap num already achieving this more or less ?

-hls_wrap num does achieve this more or less, but the option has been
proposed for two reasons:

(1) Simplify compliance with HLS Internet-Draft
(http://tools.ietf.org/html/draft-pantos-http-live-streaming) section
6.2.2., Live Playlists:

   When the server removes a Media Segment URI from the Playlist, the
   corresponding Media Segment MUST remain available to clients for a
   period of time equal to the duration of the segment plus the duration
   of the longest Playlist file distributed by the server containing
   that segment.  Removing a Media Segment earlier than that can
   interrupt in-progress playback.

The playlist length/duration can change without computation and
modification to the -hls_wrap num argument.

(2) Although not required in the HLS Internet-Draft, it can be useful to
have the sequence number in the segment URI for tracking when logging and
making modifications to playlists.

Thank you for your consideration.

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/hlsenc: added segment file deletion

2014-12-08 Thread Christian Suloway
This option flag deletes segment files removed from the playlist after a
period of time equal to the duration of the segment plus the duration of
the playlist.

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |  4 +++
 libavformat/hlsenc.c | 90 +---
 2 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 34e827c..a1264d2 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -273,6 +273,10 @@ ffmpeg -i in.nut -hls_flags single_file out.m3u8
 @end example
 Will produce the playlist, @file{out.m3u8}, and a single segment file,
 @file{out.ts}.
+
+@item hls_flags delete_segments
+Segment files removed from the playlist are deleted after a period of time
+equal to the duration of the segment plus the duration of the playlist.
 @end table
 
 @anchor{ico}
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index d5ea990..79f3a23 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -19,8 +19,12 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include config.h
 #include float.h
 #include stdint.h
+#if HAVE_UNISTD_H
+#include unistd.h
+#endif
 
 #include libavutil/avassert.h
 #include libavutil/mathematics.h
@@ -31,6 +35,7 @@
 
 #include avformat.h
 #include internal.h
+#include os_support.h
 
 typedef struct HLSSegment {
 char filename[1024];
@@ -44,6 +49,7 @@ typedef struct HLSSegment {
 typedef enum HLSFlags {
 // Generate a single media file and use byte ranges in the playlist.
 HLS_SINGLE_FILE = (1  0),
+HLS_DELETE_SEGMENTS = (1  1),
 } HLSFlags;
 
 typedef struct HLSContext {
@@ -73,6 +79,7 @@ typedef struct HLSContext {
 
 HLSSegment *segments;
 HLSSegment *last_segment;
+HLSSegment *old_segments;
 
 char *basename;
 char *baseurl;
@@ -82,6 +89,71 @@ typedef struct HLSContext {
 AVIOContext *pb;
 } HLSContext;
 
+static int hls_delete_old_segments(HLSContext *hls) {
+
+HLSSegment *segment, *previous_segment = NULL;
+float playlist_duration = 0.0f;
+int ret = 0, path_size;
+char *dirname = NULL, *p, *path;
+
+segment = hls-segments;
+while (segment) {
+playlist_duration += segment-duration;
+segment = segment-next;
+}
+
+segment = hls-old_segments;
+while (segment) {
+playlist_duration -= segment-duration;
+previous_segment = segment;
+segment = previous_segment-next;
+if (playlist_duration = -previous_segment-duration) {
+previous_segment-next = NULL;
+break;
+}
+}
+
+if (segment) {
+if (hls-segment_filename) {
+dirname = av_strdup(hls-segment_filename);
+} else {
+dirname = av_strdup(hls-avf-filename);
+}
+if (!dirname) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+p = (char *)av_basename(dirname);
+*p = '\0';
+}
+
+while (segment) {
+av_log(hls, AV_LOG_DEBUG, deleting old segment %s\n,
+  segment-filename);
+path_size = strlen(dirname) + strlen(segment-filename) + 1;
+path = av_malloc(path_size);
+if (!path) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+av_strlcpy(path, dirname, path_size);
+av_strlcat(path, segment-filename, path_size);
+if (unlink(path)  0) {
+av_log(hls, AV_LOG_ERROR, failed to delete old segment %s: %s\n,
+ path, strerror(errno));
+}
+av_free(path);
+previous_segment = segment;
+segment = previous_segment-next;
+av_free(previous_segment);
+}
+
+fail:
+av_free(dirname);
+
+return ret;
+}
+
 static int hls_mux_init(AVFormatContext *s)
 {
 HLSContext *hls = s-priv_data;
@@ -116,6 +188,7 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
   int64_t size)
 {
 HLSSegment *en = av_malloc(sizeof(*en));
+int ret;
 
 if (!en)
 return AVERROR(ENOMEM);
@@ -137,7 +210,14 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 if (hls-max_nb_segments  hls-nb_entries = hls-max_nb_segments) {
 en = hls-segments;
 hls-segments = en-next;
-av_free(en);
+if (en  hls-flags  HLS_DELETE_SEGMENTS 
+!(hls-flags  HLS_SINGLE_FILE || hls-wrap)) {
+en-next = hls-old_segments;
+hls-old_segments = en;
+if ((ret = hls_delete_old_segments(hls))  0)
+return ret;
+} else
+av_free(en);
 } else
 hls-nb_entries++;
 
@@ -146,9 +226,9 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 return 0;
 }
 
-static void hls_free_segments(HLSContext *hls)
+static void hls_free_segments

[FFmpeg-devel] [PATCH] avformat/hlsenc: added segment filename option

2014-12-05 Thread Christian Suloway
This option allows segment filenames to be specified. Unless -hls_flags
single_file is enabled the filename is used as a string format with the
segment number.

Example:
ffmpeg -f lavfi -i testsrc -c:v h264 -map 0 -hls_segment_filename
bar%03d.ts foo.m3u8

Signed-off-by: Christian Suloway csulo...@globaleagleent.com`
---
 libavformat/hlsenc.c | 46 ++
 1 file changed, 30 insertions(+), 16 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e13f438..59392c5 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -59,6 +59,7 @@ typedef struct HLSContext {
 int max_nb_segments;   // Set by a private option.
 int  wrap; // Set by a private option.
 uint32_t flags;// enum HLSFlags
+char *segment_filename;
 
 int allowcache;
 int64_t recording_time;
@@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s)
 char *p;
 const char *pattern = %d.ts;
 AVDictionary *options = NULL;
-int basename_size = strlen(s-filename) + strlen(pattern) + 1;
+int basename_size;
 
 hls-sequence   = hls-start_sequence;
 hls-recording_time = hls-time * AV_TIME_BASE;
 hls-start_pts  = AV_NOPTS_VALUE;
 
-if (hls-flags  HLS_SINGLE_FILE)
-pattern = .ts;
-
 if (hls-format_options_str) {
 ret = av_dict_parse_string(hls-format_options, 
hls-format_options_str, =, :, 0);
 if (ret  0) {
@@ -270,21 +268,36 @@ static int hls_write_header(AVFormatContext *s)
 goto fail;
 }
 
-hls-basename = av_malloc(basename_size);
-
-if (!hls-basename) {
-ret = AVERROR(ENOMEM);
-goto fail;
-}
-
-strcpy(hls-basename, s-filename);
+if (hls-segment_filename) {
+hls-basename = av_strdup(av_basename(hls-segment_filename));
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+if (strlen(hls-basename) != strlen(hls-segment_filename)) {
+av_log(hls, AV_LOG_ERROR, invalid segment filename %s\n,
+  hls-segment_filename);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+} else {
+if (hls-flags  HLS_SINGLE_FILE)
+pattern = .ts;
 
-p = strrchr(hls-basename, '.');
+basename_size = strlen(s-filename) + strlen(pattern) + 1;
+hls-basename = av_malloc(basename_size);
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 
-if (p)
-*p = '\0';
+strlcpy(hls-basename, s-filename, basename_size);
 
-av_strlcat(hls-basename, pattern, basename_size);
+p = strrchr(hls-basename, '.');
+if (p)
+*p = '\0';
+av_strlcat(hls-basename, pattern, basename_size);
+}
 
 if ((ret = hls_mux_init(s))  0)
 goto fail;
@@ -412,6 +425,7 @@ static const AVOption options[] = {
 {hls_base_url,  url to prepend to each playlist entry,   
OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,   E},
 {hls_flags, set flags affecting HLS playlist and media file 
generation, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, 
flags},
 {single_file,   generate a single media file indexed with byte ranges, 
0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX,   E, flags},
+{hls_segment_filename, filename template for segment files, 
OFFSET(segment_filename),   AV_OPT_TYPE_STRING, {.str = NULL},0,
   0, E},
 
 { NULL },
 };
-- 
1.9.3 (Apple Git-50)

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/hlsenc: added segment filename option

2014-12-05 Thread Christian Suloway
This option allows segment filenames to be specified. Unless -hls_flags
single_file is set the filename is used as a string format with the
segment number.

Example:
ffmpeg -f lavfi -i testsrc -c:v h264 -map 0 -hls_segment_filename
bar%03d.ts foo.m3u8

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |  9 +
 libavformat/hlsenc.c | 40 
 2 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index c6ba604..34e827c 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -254,6 +254,15 @@ and it is not to be confused with the segment filename 
sequence number
 which can be cyclic, for example if the @option{wrap} option is
 specified.
 
+@item hls_segment_filename @var{filename}
+Set the segment filename. Unless hls_flags single_file is set @var{filename}
+is used as a string format with the segment number:
+@example
+ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
+@end example
+This example will produce the playlist, @file{out.m3u8}, and segment files:
+@file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e13f438..786c6b4 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -59,6 +59,7 @@ typedef struct HLSContext {
 int max_nb_segments;   // Set by a private option.
 int  wrap; // Set by a private option.
 uint32_t flags;// enum HLSFlags
+char *segment_filename;
 
 int allowcache;
 int64_t recording_time;
@@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s)
 char *p;
 const char *pattern = %d.ts;
 AVDictionary *options = NULL;
-int basename_size = strlen(s-filename) + strlen(pattern) + 1;
+int basename_size;
 
 hls-sequence   = hls-start_sequence;
 hls-recording_time = hls-time * AV_TIME_BASE;
 hls-start_pts  = AV_NOPTS_VALUE;
 
-if (hls-flags  HLS_SINGLE_FILE)
-pattern = .ts;
-
 if (hls-format_options_str) {
 ret = av_dict_parse_string(hls-format_options, 
hls-format_options_str, =, :, 0);
 if (ret  0) {
@@ -270,21 +268,30 @@ static int hls_write_header(AVFormatContext *s)
 goto fail;
 }
 
-hls-basename = av_malloc(basename_size);
-
-if (!hls-basename) {
-ret = AVERROR(ENOMEM);
-goto fail;
-}
-
-strcpy(hls-basename, s-filename);
+if (hls-segment_filename) {
+hls-basename = av_strdup(av_basename(hls-segment_filename));
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+} else {
+if (hls-flags  HLS_SINGLE_FILE)
+pattern = .ts;
 
-p = strrchr(hls-basename, '.');
+basename_size = strlen(s-filename) + strlen(pattern) + 1;
+hls-basename = av_malloc(basename_size);
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 
-if (p)
-*p = '\0';
+av_strlcpy(hls-basename, s-filename, basename_size);
 
-av_strlcat(hls-basename, pattern, basename_size);
+p = strrchr(hls-basename, '.');
+if (p)
+*p = '\0';
+av_strlcat(hls-basename, pattern, basename_size);
+}
 
 if ((ret = hls_mux_init(s))  0)
 goto fail;
@@ -410,6 +417,7 @@ static const AVOption options[] = {
 {hls_wrap,  set number after which the index wraps,  OFFSET(wrap), 
   AV_OPT_TYPE_INT,{.i64 = 0}, 0, INT_MAX, E},
 {hls_allow_cache, explicitly set whether the client MAY (1) or MUST NOT 
(0) cache media segments, OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, 
INT_MIN, INT_MAX, E},
 {hls_base_url,  url to prepend to each playlist entry,   
OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,   E},
+{hls_segment_filename, filename template for segment files, 
OFFSET(segment_filename),   AV_OPT_TYPE_STRING, {.str = NULL},0,
   0, E},
 {hls_flags, set flags affecting HLS playlist and media file 
generation, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, 
flags},
 {single_file,   generate a single media file indexed with byte ranges, 
0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX,   E, flags},
 
-- 
1.9.3 (Apple Git-50)

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH] avformat/hlsenc: added segment filename option

2014-12-05 Thread Christian Suloway
This option allows segment filenames to be specified. Unless -hls_flags
single_file is set the filename is used as a string format with the
segment number.

Example:
ffmpeg -f lavfi -i testsrc -c:v h264 -map 0 -hls_segment_filename
bar%03d.ts foo.m3u8

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |  9 +
 libavformat/hlsenc.c | 40 
 2 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index c6ba604..34e827c 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -254,6 +254,15 @@ and it is not to be confused with the segment filename 
sequence number
 which can be cyclic, for example if the @option{wrap} option is
 specified.
 
+@item hls_segment_filename @var{filename}
+Set the segment filename. Unless hls_flags single_file is set @var{filename}
+is used as a string format with the segment number:
+@example
+ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
+@end example
+This example will produce the playlist, @file{out.m3u8}, and segment files:
+@file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e13f438..d5ea990 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -59,6 +59,7 @@ typedef struct HLSContext {
 int max_nb_segments;   // Set by a private option.
 int  wrap; // Set by a private option.
 uint32_t flags;// enum HLSFlags
+char *segment_filename;
 
 int allowcache;
 int64_t recording_time;
@@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s)
 char *p;
 const char *pattern = %d.ts;
 AVDictionary *options = NULL;
-int basename_size = strlen(s-filename) + strlen(pattern) + 1;
+int basename_size;
 
 hls-sequence   = hls-start_sequence;
 hls-recording_time = hls-time * AV_TIME_BASE;
 hls-start_pts  = AV_NOPTS_VALUE;
 
-if (hls-flags  HLS_SINGLE_FILE)
-pattern = .ts;
-
 if (hls-format_options_str) {
 ret = av_dict_parse_string(hls-format_options, 
hls-format_options_str, =, :, 0);
 if (ret  0) {
@@ -270,21 +268,30 @@ static int hls_write_header(AVFormatContext *s)
 goto fail;
 }
 
-hls-basename = av_malloc(basename_size);
-
-if (!hls-basename) {
-ret = AVERROR(ENOMEM);
-goto fail;
-}
-
-strcpy(hls-basename, s-filename);
+if (hls-segment_filename) {
+hls-basename = av_strdup(hls-segment_filename);
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+} else {
+if (hls-flags  HLS_SINGLE_FILE)
+pattern = .ts;
 
-p = strrchr(hls-basename, '.');
+basename_size = strlen(s-filename) + strlen(pattern) + 1;
+hls-basename = av_malloc(basename_size);
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
 
-if (p)
-*p = '\0';
+av_strlcpy(hls-basename, s-filename, basename_size);
 
-av_strlcat(hls-basename, pattern, basename_size);
+p = strrchr(hls-basename, '.');
+if (p)
+*p = '\0';
+av_strlcat(hls-basename, pattern, basename_size);
+}
 
 if ((ret = hls_mux_init(s))  0)
 goto fail;
@@ -410,6 +417,7 @@ static const AVOption options[] = {
 {hls_wrap,  set number after which the index wraps,  OFFSET(wrap), 
   AV_OPT_TYPE_INT,{.i64 = 0}, 0, INT_MAX, E},
 {hls_allow_cache, explicitly set whether the client MAY (1) or MUST NOT 
(0) cache media segments, OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, 
INT_MIN, INT_MAX, E},
 {hls_base_url,  url to prepend to each playlist entry,   
OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,   E},
+{hls_segment_filename, filename template for segment files, 
OFFSET(segment_filename),   AV_OPT_TYPE_STRING, {.str = NULL},0,
   0, E},
 {hls_flags, set flags affecting HLS playlist and media file 
generation, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, 
flags},
 {single_file,   generate a single media file indexed with byte ranges, 
0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX,   E, flags},
 
-- 
1.9.3 (Apple Git-50)

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH] avformat/hlsenc: added segment filename option

2014-12-05 Thread Christian Suloway
Updating from previous message.

From: Christian Suloway csulo...@row44.com
Sent: Friday, December 5, 2014 3:17 PM
To: ffmpeg-devel@ffmpeg.org
Cc: Christian Suloway
Subject: [PATCH] avformat/hlsenc: added segment filename option

This option allows segment filenames to be specified. Unless -hls_flags
single_file is set the filename is used as a string format with the
segment number.

Example:
ffmpeg -f lavfi -i testsrc -c:v h264 -map 0 -hls_segment_filename
bar%03d.ts foo.m3u8

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 doc/muxers.texi  |  9 +
 libavformat/hlsenc.c | 40 
 2 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index c6ba604..34e827c 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -254,6 +254,15 @@ and it is not to be confused with the segment filename 
sequence number
 which can be cyclic, for example if the @option{wrap} option is
 specified.

+@item hls_segment_filename @var{filename}
+Set the segment filename. Unless hls_flags single_file is set @var{filename}
+is used as a string format with the segment number:
+@example
+ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
+@end example
+This example will produce the playlist, @file{out.m3u8}, and segment files:
+@file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
+
 @item hls_flags single_file
 If this flag is set, the muxer will store all segments in a single MPEG-TS
 file, and will use byte ranges in the playlist. HLS playlists generated with
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e13f438..d5ea990 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -59,6 +59,7 @@ typedef struct HLSContext {
 int max_nb_segments;   // Set by a private option.
 int  wrap; // Set by a private option.
 uint32_t flags;// enum HLSFlags
+char *segment_filename;

 int allowcache;
 int64_t recording_time;
@@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s)
 char *p;
 const char *pattern = %d.ts;
 AVDictionary *options = NULL;
-int basename_size = strlen(s-filename) + strlen(pattern) + 1;
+int basename_size;

 hls-sequence   = hls-start_sequence;
 hls-recording_time = hls-time * AV_TIME_BASE;
 hls-start_pts  = AV_NOPTS_VALUE;

-if (hls-flags  HLS_SINGLE_FILE)
-pattern = .ts;
-
 if (hls-format_options_str) {
 ret = av_dict_parse_string(hls-format_options, 
hls-format_options_str, =, :, 0);
 if (ret  0) {
@@ -270,21 +268,30 @@ static int hls_write_header(AVFormatContext *s)
 goto fail;
 }

-hls-basename = av_malloc(basename_size);
-
-if (!hls-basename) {
-ret = AVERROR(ENOMEM);
-goto fail;
-}
-
-strcpy(hls-basename, s-filename);
+if (hls-segment_filename) {
+hls-basename = av_strdup(hls-segment_filename);
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+} else {
+if (hls-flags  HLS_SINGLE_FILE)
+pattern = .ts;

-p = strrchr(hls-basename, '.');
+basename_size = strlen(s-filename) + strlen(pattern) + 1;
+hls-basename = av_malloc(basename_size);
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}

-if (p)
-*p = '\0';
+av_strlcpy(hls-basename, s-filename, basename_size);

-av_strlcat(hls-basename, pattern, basename_size);
+p = strrchr(hls-basename, '.');
+if (p)
+*p = '\0';
+av_strlcat(hls-basename, pattern, basename_size);
+}

 if ((ret = hls_mux_init(s))  0)
 goto fail;
@@ -410,6 +417,7 @@ static const AVOption options[] = {
 {hls_wrap,  set number after which the index wraps,  OFFSET(wrap), 
   AV_OPT_TYPE_INT,{.i64 = 0}, 0, INT_MAX, E},
 {hls_allow_cache, explicitly set whether the client MAY (1) or MUST NOT 
(0) cache media segments, OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, 
INT_MIN, INT_MAX, E},
 {hls_base_url,  url to prepend to each playlist entry,   
OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,   E},
+{hls_segment_filename, filename template for segment files, 
OFFSET(segment_filename),   AV_OPT_TYPE_STRING, {.str = NULL},0,
   0, E},
 {hls_flags, set flags affecting HLS playlist and media file 
generation, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, 
flags},
 {single_file,   generate a single media file indexed with byte ranges, 
0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX,   E, flags},

--
1.9.3 (Apple Git-50)

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/3] avformat/hlsenc: added segment filename template

2014-12-04 Thread Christian Suloway
Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/hlsenc.c | 87 +---
 1 file changed, 69 insertions(+), 18 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e13f438..0a48919 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -33,7 +33,7 @@
 #include internal.h
 
 typedef struct HLSSegment {
-char filename[1024];
+char *filename;
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
@@ -73,14 +73,23 @@ typedef struct HLSContext {
 HLSSegment *segments;
 HLSSegment *last_segment;
 
+char *dirname;
 char *basename;
 char *baseurl;
 char *format_options_str;
 AVDictionary *format_options;
 
+char *segment_filename;
+
 AVIOContext *pb;
 } HLSContext;
 
+static void hls_free_segment(HLSSegment *en)
+{
+av_freep(en-filename);
+av_freep(en);
+}
+
 static int hls_mux_init(AVFormatContext *s)
 {
 HLSContext *hls = s-priv_data;
@@ -119,7 +128,9 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 if (!en)
 return AVERROR(ENOMEM);
 
-av_strlcpy(en-filename, av_basename(hls-avf-filename), 
sizeof(en-filename));
+en-filename = av_strdup(hls-avf-filename);
+if (!en-filename)
+return AVERROR(ENOMEM);
 
 en-duration = duration;
 en-pos  = pos;
@@ -136,7 +147,7 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 if (hls-max_nb_segments  hls-nb_entries = hls-max_nb_segments) {
 en = hls-segments;
 hls-segments = en-next;
-av_free(en);
+hls_free_segment(en);
 } else
 hls-nb_entries++;
 
@@ -152,7 +163,7 @@ static void hls_free_segments(HLSContext *hls)
 while(p) {
 en = p;
 p = p-next;
-av_free(en);
+hls_free_segment(en);
 }
 }
 
@@ -186,6 +197,7 @@ static int hls_window(AVFormatContext *s, int last)
sequence);
 
 for (en = hls-segments; en; en = en-next) {
+
 avio_printf(hls-pb, #EXTINF:%f,\n, en-duration);
 if (hls-flags  HLS_SINGLE_FILE)
  avio_printf(hls-pb, #EXT-X-BYTERANGE:%PRIi64@%PRIi64\n,
@@ -208,6 +220,8 @@ static int hls_start(AVFormatContext *s)
 HLSContext *c = s-priv_data;
 AVFormatContext *oc = c-avf;
 int err = 0;
+int filename_size;
+char *filename;
 
 if (c-flags  HLS_SINGLE_FILE)
 av_strlcpy(oc-filename, c-basename,
@@ -220,8 +234,18 @@ static int hls_start(AVFormatContext *s)
 }
 c-number++;
 
-if ((err = avio_open2(oc-pb, oc-filename, AVIO_FLAG_WRITE,
-  s-interrupt_callback, NULL))  0)
+filename_size = strlen(c-dirname) + strlen(oc-filename) + 1;
+filename = av_malloc(filename_size);
+if (!filename)
+return AVERROR(ENOMEM);
+*filename = '\0';
+av_strlcat(filename, c-dirname, filename_size);
+av_strlcat(filename, oc-filename, filename_size);
+
+err = avio_open2(oc-pb, filename, AVIO_FLAG_WRITE,
+ s-interrupt_callback, NULL);
+av_free(filename);
+if (err  0)
 return err;
 
 if (oc-oformat-priv_class  oc-priv_data)
@@ -237,15 +261,13 @@ static int hls_write_header(AVFormatContext *s)
 char *p;
 const char *pattern = %d.ts;
 AVDictionary *options = NULL;
-int basename_size = strlen(s-filename) + strlen(pattern) + 1;
+int basename_size;
+char *basename;
 
 hls-sequence   = hls-start_sequence;
 hls-recording_time = hls-time * AV_TIME_BASE;
 hls-start_pts  = AV_NOPTS_VALUE;
 
-if (hls-flags  HLS_SINGLE_FILE)
-pattern = .ts;
-
 if (hls-format_options_str) {
 ret = av_dict_parse_string(hls-format_options, 
hls-format_options_str, =, :, 0);
 if (ret  0) {
@@ -270,21 +292,45 @@ static int hls_write_header(AVFormatContext *s)
 goto fail;
 }
 
-hls-basename = av_malloc(basename_size);
-
-if (!hls-basename) {
+hls-dirname = av_strdup(s-filename);
+if (!hls-dirname) {
 ret = AVERROR(ENOMEM);
 goto fail;
 }
 
-strcpy(hls-basename, s-filename);
+basename = (char *)av_basename(hls-dirname);
 
-p = strrchr(hls-basename, '.');
+if (hls-segment_filename) {
+hls-basename = av_strdup(av_basename(hls-segment_filename));
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+if (strlen(hls-basename) != strlen(hls-segment_filename)) {
+av_log(hls, AV_LOG_ERROR, invalid segment filename %s\n,
+  hls-segment_filename);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+} else {
+if (hls-flags  HLS_SINGLE_FILE)
+pattern = .ts;
 
-if (p)
-*p = '\0';
+basename_size = strlen(basename) + strlen(pattern) + 1;
+hls-basename = av_malloc(basename_size

[FFmpeg-devel] [PATCH 3/3] avformat/hlsenc: added HLS encryption

2014-12-04 Thread Christian Suloway
HLS encryption with key URL  key containing file specified with
-hls_key_info_file (key info updates when modified). Option for IV from
segment number or random generation (-hls_random_iv).

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/hlsenc.c | 225 +--
 1 file changed, 218 insertions(+), 7 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 11817a9..c7bd1be 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -33,16 +33,23 @@
 #include libavutil/avstring.h
 #include libavutil/opt.h
 #include libavutil/log.h
+#include libavutil/lfg.h
+#include libavutil/random_seed.h
 
 #include avformat.h
 #include internal.h
 
+#define BLOCKSIZE 16
+
 typedef struct HLSSegment {
 char *filename;
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char *key_uri;
+char *iv_string;
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -88,12 +95,25 @@ typedef struct HLSContext {
 
 char *segment_filename;
 
+char *key_info_file;
+int random_iv;
+int encrypt;
+
+char *key_file;
+char *key_uri;
+char *key_string;
+char *iv_string;
+
+AVLFG *lfg;
+
 AVIOContext *pb;
 } HLSContext;
 
 static void hls_free_segment(HLSSegment *en)
 {
 av_freep(en-filename);
+av_freep(en-key_uri);
+av_freep(en-iv_string);
 av_freep(en);
 }
 
@@ -143,6 +163,137 @@ static int hls_delete_old_segments(HLSContext *hls) {
 return 0;
 }
 
+static int hls_encryption_init(AVFormatContext *s)
+{
+HLSContext *hls = s-priv_data;
+
+hls-key_file = NULL;
+hls-key_uri = NULL;
+hls-key_string = NULL;
+hls-iv_string = NULL;
+
+if (hls-key_info_file) {
+hls-encrypt = 1;
+} else {
+hls-encrypt = 0;
+return 0;
+}
+
+if (hls-random_iv) {
+hls-lfg = av_malloc(sizeof(AVLFG));
+av_lfg_init(hls-lfg, av_get_random_seed());
+} else
+hls-lfg = NULL;
+
+return 0;
+}
+
+static int hls_encryption_start(HLSContext *hls) {
+
+uint8_t *iv = NULL;
+int ret, i, j, rotate_iv = 0;
+unsigned int u;
+AVIOContext *pb = NULL;
+AVIOContext *dyn_buf = NULL;
+uint8_t buf[1024], *tmp;
+char *p, *tstr, *saveptr = NULL;
+char key[BLOCKSIZE], *key_string;
+
+if ((ret = avio_open(pb, hls-key_info_file, AVIO_FLAG_READ))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key info file %s\n,
+  hls-key_info_file);
+return ret;
+}
+ret = avio_open_dyn_buf(dyn_buf);
+if (ret  0) {
+avio_closep(pb);
+return ret;
+}
+
+while ((ret = avio_read(pb, buf, sizeof(buf)))  0)
+avio_write(dyn_buf, buf, ret);
+avio_w8(dyn_buf, 0);
+avio_closep(pb);
+
+if ((ret = avio_close_dyn_buf(dyn_buf, tmp))  0)
+return ret;
+
+p = tmp;
+if (!(tstr = av_strtok(p, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key URL specified in key info file %s\n,
+  hls-key_info_file);
+return AVERROR(EINVAL);
+}
+p = NULL;
+av_free(hls-key_uri);
+hls-key_uri = av_strdup(tstr);
+if (!hls-key_uri)
+return AVERROR(ENOMEM);
+if (!(tstr = av_strtok(p, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key file specified in key info file 
%s\n,
+  hls-key_info_file);
+return AVERROR(EINVAL);
+}
+av_free(hls-key_file);
+hls-key_file = av_strdup(tstr);
+if (!hls-key_file)
+return AVERROR(ENOMEM);
+av_free(tmp);
+
+if ((ret = avio_open(pb, hls-key_file, AVIO_FLAG_READ))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key file %s\n,
+  hls-key_file);
+return ret;
+}
+
+ret = avio_read(pb, key, sizeof(key));
+avio_closep(pb);
+if (ret  sizeof(key)) {
+av_log(hls, AV_LOG_ERROR, error reading key file %s\n,
+  hls-key_file);
+return ret;
+}
+
+key_string = av_mallocz(BLOCKSIZE*2 + 1);
+if (!key_string)
+return AVERROR(ENOMEM);
+ff_data_to_hex(key_string, key, BLOCKSIZE, 0);
+if (!hls-key_string || strncmp(key_string, hls-key_string, BLOCKSIZE*2)) 
{
+av_free(hls-key_string);
+hls-key_string = key_string;
+rotate_iv = 1;
+} else {
+av_free(key_string);
+}
+
+if (!hls-random_iv) {
+iv = av_mallocz(BLOCKSIZE);
+if (!iv)
+return AVERROR(ENOMEM);
+for (i = 0; i  8; i++)
+iv[BLOCKSIZE - 1 - i ] = (hls-sequence  i*8)  0xff;
+} else if (!hls-iv_string || rotate_iv) {
+iv = av_malloc(BLOCKSIZE);
+if (!iv)
+return AVERROR(ENOMEM);
+for (i = 0; i  BLOCKSIZE/4; i++) {
+u = av_lfg_get(hls-lfg);
+for (j = 0; j  4; j++)
+iv[i*4 + j

[FFmpeg-devel] [PATCH 2/3] avformat/hlsenc: added segment file deletion

2014-12-04 Thread Christian Suloway
Option removes segments no longer in playlist when older than playlist + 
segment duration

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/hlsenc.c | 72 
 1 file changed, 67 insertions(+), 5 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 0a48919..11817a9 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -19,8 +19,13 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include config.h
 #include float.h
 #include stdint.h
+#if HAVE_UNISTD_H
+#include unistd.h
+#endif
+#include stdio.h
 
 #include libavutil/avassert.h
 #include libavutil/mathematics.h
@@ -58,6 +63,7 @@ typedef struct HLSContext {
 float time;// Set by a private option.
 int max_nb_segments;   // Set by a private option.
 int  wrap; // Set by a private option.
+int delete_segments;
 uint32_t flags;// enum HLSFlags
 
 int allowcache;
@@ -72,6 +78,7 @@ typedef struct HLSContext {
 
 HLSSegment *segments;
 HLSSegment *last_segment;
+HLSSegment *old_segments;
 
 char *dirname;
 char *basename;
@@ -90,6 +97,52 @@ static void hls_free_segment(HLSSegment *en)
 av_freep(en);
 }
 
+static int hls_delete_old_segments(HLSContext *hls) {
+
+HLSSegment *segment, *previous_segment = NULL;
+float playlist_duration = 0.0f;
+int path_size;
+char *path;
+
+segment = hls-segments;
+while (segment) {
+playlist_duration += segment-duration;
+segment = segment-next;
+}
+
+segment = hls-old_segments;
+while (segment) {
+playlist_duration -= segment-duration;
+previous_segment = segment;
+segment = segment-next;
+if (playlist_duration = 0.0f) {
+previous_segment-next = NULL;
+break;
+}
+}
+
+while (segment) {
+av_log(hls, AV_LOG_DEBUG, deleting old segment %s\n,
+  segment-filename);
+path_size = strlen(hls-dirname) + strlen(segment-filename) + 1;
+path = av_malloc(path_size);
+if (!path)
+return AVERROR(ENOMEM);
+av_strlcpy(path, hls-dirname, path_size);
+av_strlcat(path, segment-filename, path_size);
+if (unlink(path)  0) {
+av_log(hls, AV_LOG_ERROR, failed to delete old segment %s: %s\n,
+ path, strerror(errno));
+}
+av_free(path);
+previous_segment = segment;
+segment = segment-next;
+hls_free_segment(previous_segment);
+}
+
+return 0;
+}
+
 static int hls_mux_init(AVFormatContext *s)
 {
 HLSContext *hls = s-priv_data;
@@ -124,6 +177,7 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
   int64_t size)
 {
 HLSSegment *en = av_malloc(sizeof(*en));
+int ret;
 
 if (!en)
 return AVERROR(ENOMEM);
@@ -147,7 +201,14 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 if (hls-max_nb_segments  hls-nb_entries = hls-max_nb_segments) {
 en = hls-segments;
 hls-segments = en-next;
-hls_free_segment(en);
+
+if (en  hls-delete_segments  !hls-wrap) {
+en-next = hls-old_segments;
+hls-old_segments = en;
+if ((ret = hls_delete_old_segments(hls))  0)
+return ret;
+} else
+hls_free_segment(en);
 } else
 hls-nb_entries++;
 
@@ -156,9 +217,9 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 return 0;
 }
 
-static void hls_free_segments(HLSContext *hls)
+static void hls_free_segments(HLSSegment *p)
 {
-HLSSegment *p = hls-segments, *en;
+HLSSegment *en;
 
 while(p) {
 en = p;
@@ -197,7 +258,6 @@ static int hls_window(AVFormatContext *s, int last)
sequence);
 
 for (en = hls-segments; en; en = en-next) {
-
 avio_printf(hls-pb, #EXTINF:%f,\n, en-duration);
 if (hls-flags  HLS_SINGLE_FILE)
  avio_printf(hls-pb, #EXT-X-BYTERANGE:%PRIi64@%PRIi64\n,
@@ -442,7 +502,8 @@ static int hls_write_trailer(struct AVFormatContext *s)
 hls-avf = NULL;
 hls_window(s, 1);
 
-hls_free_segments(hls);
+hls_free_segments(hls-segments);
+hls_free_segments(hls-old_segments);
 av_free(hls-dirname);
 
 avio_close(hls-pb);
@@ -458,6 +519,7 @@ static const AVOption options[] = {
 {hls_list_size, set maximum number of playlist entries,  
OFFSET(max_nb_segments),AV_OPT_TYPE_INT,{.i64 = 5}, 0, INT_MAX, E},
 {hls_ts_options,set hls mpegts list of options for the container format 
used for hls, OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL},  
0, 0,E},
 {hls_wrap,  set number after which the index wraps,  OFFSET(wrap), 
   AV_OPT_TYPE_INT,{.i64 = 0}, 0

[FFmpeg-devel] [PATCH 2/4] avformat/hlsenc: added segment filename template

2014-12-01 Thread Christian Suloway
Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/hlsenc.c | 87 +---
 1 file changed, 69 insertions(+), 18 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e13f438..0a48919 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -33,7 +33,7 @@
 #include internal.h
 
 typedef struct HLSSegment {
-char filename[1024];
+char *filename;
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
@@ -73,14 +73,23 @@ typedef struct HLSContext {
 HLSSegment *segments;
 HLSSegment *last_segment;
 
+char *dirname;
 char *basename;
 char *baseurl;
 char *format_options_str;
 AVDictionary *format_options;
 
+char *segment_filename;
+
 AVIOContext *pb;
 } HLSContext;
 
+static void hls_free_segment(HLSSegment *en)
+{
+av_freep(en-filename);
+av_freep(en);
+}
+
 static int hls_mux_init(AVFormatContext *s)
 {
 HLSContext *hls = s-priv_data;
@@ -119,7 +128,9 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 if (!en)
 return AVERROR(ENOMEM);
 
-av_strlcpy(en-filename, av_basename(hls-avf-filename), 
sizeof(en-filename));
+en-filename = av_strdup(hls-avf-filename);
+if (!en-filename)
+return AVERROR(ENOMEM);
 
 en-duration = duration;
 en-pos  = pos;
@@ -136,7 +147,7 @@ static int hls_append_segment(HLSContext *hls, double 
duration, int64_t pos,
 if (hls-max_nb_segments  hls-nb_entries = hls-max_nb_segments) {
 en = hls-segments;
 hls-segments = en-next;
-av_free(en);
+hls_free_segment(en);
 } else
 hls-nb_entries++;
 
@@ -152,7 +163,7 @@ static void hls_free_segments(HLSContext *hls)
 while(p) {
 en = p;
 p = p-next;
-av_free(en);
+hls_free_segment(en);
 }
 }
 
@@ -186,6 +197,7 @@ static int hls_window(AVFormatContext *s, int last)
sequence);
 
 for (en = hls-segments; en; en = en-next) {
+
 avio_printf(hls-pb, #EXTINF:%f,\n, en-duration);
 if (hls-flags  HLS_SINGLE_FILE)
  avio_printf(hls-pb, #EXT-X-BYTERANGE:%PRIi64@%PRIi64\n,
@@ -208,6 +220,8 @@ static int hls_start(AVFormatContext *s)
 HLSContext *c = s-priv_data;
 AVFormatContext *oc = c-avf;
 int err = 0;
+int filename_size;
+char *filename;
 
 if (c-flags  HLS_SINGLE_FILE)
 av_strlcpy(oc-filename, c-basename,
@@ -220,8 +234,18 @@ static int hls_start(AVFormatContext *s)
 }
 c-number++;
 
-if ((err = avio_open2(oc-pb, oc-filename, AVIO_FLAG_WRITE,
-  s-interrupt_callback, NULL))  0)
+filename_size = strlen(c-dirname) + strlen(oc-filename) + 1;
+filename = av_malloc(filename_size);
+if (!filename)
+return AVERROR(ENOMEM);
+*filename = '\0';
+av_strlcat(filename, c-dirname, filename_size);
+av_strlcat(filename, oc-filename, filename_size);
+
+err = avio_open2(oc-pb, filename, AVIO_FLAG_WRITE,
+ s-interrupt_callback, NULL);
+av_free(filename);
+if (err  0)
 return err;
 
 if (oc-oformat-priv_class  oc-priv_data)
@@ -237,15 +261,13 @@ static int hls_write_header(AVFormatContext *s)
 char *p;
 const char *pattern = %d.ts;
 AVDictionary *options = NULL;
-int basename_size = strlen(s-filename) + strlen(pattern) + 1;
+int basename_size;
+char *basename;
 
 hls-sequence   = hls-start_sequence;
 hls-recording_time = hls-time * AV_TIME_BASE;
 hls-start_pts  = AV_NOPTS_VALUE;
 
-if (hls-flags  HLS_SINGLE_FILE)
-pattern = .ts;
-
 if (hls-format_options_str) {
 ret = av_dict_parse_string(hls-format_options, 
hls-format_options_str, =, :, 0);
 if (ret  0) {
@@ -270,21 +292,45 @@ static int hls_write_header(AVFormatContext *s)
 goto fail;
 }
 
-hls-basename = av_malloc(basename_size);
-
-if (!hls-basename) {
+hls-dirname = av_strdup(s-filename);
+if (!hls-dirname) {
 ret = AVERROR(ENOMEM);
 goto fail;
 }
 
-strcpy(hls-basename, s-filename);
+basename = (char *)av_basename(hls-dirname);
 
-p = strrchr(hls-basename, '.');
+if (hls-segment_filename) {
+hls-basename = av_strdup(av_basename(hls-segment_filename));
+if (!hls-basename) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+if (strlen(hls-basename) != strlen(hls-segment_filename)) {
+av_log(hls, AV_LOG_ERROR, invalid segment filename %s\n,
+  hls-segment_filename);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+} else {
+if (hls-flags  HLS_SINGLE_FILE)
+pattern = .ts;
 
-if (p)
-*p = '\0';
+basename_size = strlen(basename) + strlen(pattern) + 1;
+hls-basename = av_malloc(basename_size

[FFmpeg-devel] [PATCH 1/4] avformat/crypto: added encryption

2014-12-01 Thread Christian Suloway
Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/crypto.c | 166 ---
 1 file changed, 146 insertions(+), 20 deletions(-)

diff --git a/libavformat/crypto.c b/libavformat/crypto.c
index a9b6e47..f3a85c7 100644
--- a/libavformat/crypto.c
+++ b/libavformat/crypto.c
@@ -41,14 +41,32 @@ typedef struct {
 int keylen;
 uint8_t *iv;
 int ivlen;
-struct AVAES *aes;
+uint8_t *decrypt_key;
+int decrypt_keylen;
+uint8_t *decrypt_iv;
+int decrypt_ivlen;
+uint8_t *encrypt_key;
+int encrypt_keylen;
+uint8_t *encrypt_iv;
+int encrypt_ivlen;
+struct AVAES *aes_decrypt;
+struct AVAES *aes_encrypt;
+
+uint8_t pad[BLOCKSIZE];
+int pad_len;
+
 } CryptoContext;
 
 #define OFFSET(x) offsetof(CryptoContext, x)
 #define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
-{key, AES decryption key, OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D 
},
-{iv,  AES decryption initialization vector, OFFSET(iv), 
AV_OPT_TYPE_BINARY, .flags = D },
+{key, AES encryption/decryption key,   OFFSET(key),
 AV_OPT_TYPE_BINARY, .flags = D|E },
+{iv,  AES encryption/decryption initialization vector, OFFSET(iv), 
 AV_OPT_TYPE_BINARY, .flags = D|E },
+{decryption_key, AES decryption key,   
OFFSET(decrypt_key), AV_OPT_TYPE_BINARY, .flags = D },
+{decryption_iv,  AES decryption initialization vector, 
OFFSET(decrypt_iv),  AV_OPT_TYPE_BINARY, .flags = D },
+{encryption_key, AES encryption key,   
OFFSET(encrypt_key), AV_OPT_TYPE_BINARY, .flags = E },
+{encryption_iv,  AES encryption initialization vector, 
OFFSET(encrypt_iv),  AV_OPT_TYPE_BINARY, .flags = E },
 { NULL }
 };
 
@@ -59,6 +77,34 @@ static const AVClass crypto_class = {
 .version= LIBAVUTIL_VERSION_INT,
 };
 
+static int set_aes_arg(CryptoContext *c, uint8_t **buf, int *buf_len,
+   uint8_t *default_buf, int default_buf_len,
+   const char *desc)
+{
+if (!*buf_len) {
+if (!default_buf_len) {
+av_log(c, AV_LOG_ERROR, %s not set\n, desc);
+return AVERROR(EINVAL);
+} else if (default_buf_len != BLOCKSIZE) {
+av_log(c, AV_LOG_ERROR,
+   invalid %s size (%d bytes, block size is %d)\n,
+   desc, default_buf_len, BLOCKSIZE);
+return AVERROR(EINVAL);
+}
+*buf = av_malloc(default_buf_len);
+if (!*buf)
+return AVERROR(ENOMEM);
+memcpy(*buf, default_buf, default_buf_len);
+*buf_len = default_buf_len;
+} else if (*buf_len != BLOCKSIZE) {
+av_log(c, AV_LOG_ERROR,
+   invalid %s size (%d bytes, block size is %d)\n,
+   desc, *buf_len, BLOCKSIZE);
+return AVERROR(EINVAL);
+}
+return 0;
+}
+
 static int crypto_open2(URLContext *h, const char *uri, int flags, 
AVDictionary **options)
 {
 const char *nested_url;
@@ -72,28 +118,54 @@ static int crypto_open2(URLContext *h, const char *uri, 
int flags, AVDictionary
 goto err;
 }
 
-if (c-keylen  BLOCKSIZE || c-ivlen  BLOCKSIZE) {
-av_log(h, AV_LOG_ERROR, Key or IV not set\n);
-ret = AVERROR(EINVAL);
-goto err;
+if (flags  AVIO_FLAG_READ) {
+if ((ret = set_aes_arg(c, c-decrypt_key, c-decrypt_keylen,
+   c-key, c-keylen, decryption key))  0)
+goto err;
+if ((ret = set_aes_arg(c, c-decrypt_iv, c-decrypt_ivlen,
+   c-key, c-keylen, decryption IV))  0)
+goto err;
 }
+
 if (flags  AVIO_FLAG_WRITE) {
-av_log(h, AV_LOG_ERROR, Only decryption is supported currently\n);
-ret = AVERROR(ENOSYS);
-goto err;
+if ((ret = set_aes_arg(c, c-encrypt_key, c-encrypt_keylen,
+   c-key, c-keylen, encryption key))  0)
+if (ret  0)
+goto err;
+if ((ret = set_aes_arg(c, c-encrypt_iv, c-encrypt_ivlen,
+   c-key, c-keylen, encryption IV))  0)
+goto err;
 }
-if ((ret = ffurl_open(c-hd, nested_url, AVIO_FLAG_READ,
+
+if ((ret = ffurl_open(c-hd, nested_url, flags,
   h-interrupt_callback, options))  0) {
-av_log(h, AV_LOG_ERROR, Unable to open input\n);
+av_log(h, AV_LOG_ERROR, Unable to open resource: %s\n, nested_url);
 goto err;
 }
-c-aes = av_aes_alloc();
-if (!c-aes) {
-ret = AVERROR(ENOMEM);
-goto err;
+
+if (flags  AVIO_FLAG_READ) {
+c-aes_decrypt = av_aes_alloc();
+if (!c-aes_decrypt) {
+ret = AVERROR(ENOMEM);
+goto err;
+}
+ret = av_aes_init(c-aes_decrypt, c-decrypt_key, BLOCKSIZE*8, 1);
+if (ret  0)
+goto

[FFmpeg-devel] [PATCH 4/4] avformat/hlsenc: added HLS encryption

2014-12-01 Thread Christian Suloway
HLS encryption with key URL  key containing file specified with
-hls_key_info_file (key info updates when modified). Option for IV from
segment number or random generation (-hls_random_iv).

Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/hlsenc.c | 225 +--
 1 file changed, 218 insertions(+), 7 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 11817a9..c7bd1be 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -33,16 +33,23 @@
 #include libavutil/avstring.h
 #include libavutil/opt.h
 #include libavutil/log.h
+#include libavutil/lfg.h
+#include libavutil/random_seed.h
 
 #include avformat.h
 #include internal.h
 
+#define BLOCKSIZE 16
+
 typedef struct HLSSegment {
 char *filename;
 double duration; /* in seconds */
 int64_t pos;
 int64_t size;
 
+char *key_uri;
+char *iv_string;
+
 struct HLSSegment *next;
 } HLSSegment;
 
@@ -88,12 +95,25 @@ typedef struct HLSContext {
 
 char *segment_filename;
 
+char *key_info_file;
+int random_iv;
+int encrypt;
+
+char *key_file;
+char *key_uri;
+char *key_string;
+char *iv_string;
+
+AVLFG *lfg;
+
 AVIOContext *pb;
 } HLSContext;
 
 static void hls_free_segment(HLSSegment *en)
 {
 av_freep(en-filename);
+av_freep(en-key_uri);
+av_freep(en-iv_string);
 av_freep(en);
 }
 
@@ -143,6 +163,137 @@ static int hls_delete_old_segments(HLSContext *hls) {
 return 0;
 }
 
+static int hls_encryption_init(AVFormatContext *s)
+{
+HLSContext *hls = s-priv_data;
+
+hls-key_file = NULL;
+hls-key_uri = NULL;
+hls-key_string = NULL;
+hls-iv_string = NULL;
+
+if (hls-key_info_file) {
+hls-encrypt = 1;
+} else {
+hls-encrypt = 0;
+return 0;
+}
+
+if (hls-random_iv) {
+hls-lfg = av_malloc(sizeof(AVLFG));
+av_lfg_init(hls-lfg, av_get_random_seed());
+} else
+hls-lfg = NULL;
+
+return 0;
+}
+
+static int hls_encryption_start(HLSContext *hls) {
+
+uint8_t *iv = NULL;
+int ret, i, j, rotate_iv = 0;
+unsigned int u;
+AVIOContext *pb = NULL;
+AVIOContext *dyn_buf = NULL;
+uint8_t buf[1024], *tmp;
+char *p, *tstr, *saveptr = NULL;
+char key[BLOCKSIZE], *key_string;
+
+if ((ret = avio_open(pb, hls-key_info_file, AVIO_FLAG_READ))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key info file %s\n,
+  hls-key_info_file);
+return ret;
+}
+ret = avio_open_dyn_buf(dyn_buf);
+if (ret  0) {
+avio_closep(pb);
+return ret;
+}
+
+while ((ret = avio_read(pb, buf, sizeof(buf)))  0)
+avio_write(dyn_buf, buf, ret);
+avio_w8(dyn_buf, 0);
+avio_closep(pb);
+
+if ((ret = avio_close_dyn_buf(dyn_buf, tmp))  0)
+return ret;
+
+p = tmp;
+if (!(tstr = av_strtok(p, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key URL specified in key info file %s\n,
+  hls-key_info_file);
+return AVERROR(EINVAL);
+}
+p = NULL;
+av_free(hls-key_uri);
+hls-key_uri = av_strdup(tstr);
+if (!hls-key_uri)
+return AVERROR(ENOMEM);
+if (!(tstr = av_strtok(p, \n, saveptr)) || !*tstr) {
+av_log(hls, AV_LOG_ERROR, no key file specified in key info file 
%s\n,
+  hls-key_info_file);
+return AVERROR(EINVAL);
+}
+av_free(hls-key_file);
+hls-key_file = av_strdup(tstr);
+if (!hls-key_file)
+return AVERROR(ENOMEM);
+av_free(tmp);
+
+if ((ret = avio_open(pb, hls-key_file, AVIO_FLAG_READ))  0) {
+av_log(hls, AV_LOG_ERROR, error opening key file %s\n,
+  hls-key_file);
+return ret;
+}
+
+ret = avio_read(pb, key, sizeof(key));
+avio_closep(pb);
+if (ret  sizeof(key)) {
+av_log(hls, AV_LOG_ERROR, error reading key file %s\n,
+  hls-key_file);
+return ret;
+}
+
+key_string = av_mallocz(BLOCKSIZE*2 + 1);
+if (!key_string)
+return AVERROR(ENOMEM);
+ff_data_to_hex(key_string, key, BLOCKSIZE, 0);
+if (!hls-key_string || strncmp(key_string, hls-key_string, BLOCKSIZE*2)) 
{
+av_free(hls-key_string);
+hls-key_string = key_string;
+rotate_iv = 1;
+} else {
+av_free(key_string);
+}
+
+if (!hls-random_iv) {
+iv = av_mallocz(BLOCKSIZE);
+if (!iv)
+return AVERROR(ENOMEM);
+for (i = 0; i  8; i++)
+iv[BLOCKSIZE - 1 - i ] = (hls-sequence  i*8)  0xff;
+} else if (!hls-iv_string || rotate_iv) {
+iv = av_malloc(BLOCKSIZE);
+if (!iv)
+return AVERROR(ENOMEM);
+for (i = 0; i  BLOCKSIZE/4; i++) {
+u = av_lfg_get(hls-lfg);
+for (j = 0; j  4; j++)
+iv[i*4 + j

[FFmpeg-devel] [PATCH] avformat/hlsenc: added HLS encryption

2014-11-26 Thread Christian Suloway
Signed-off-by: Christian Suloway csulo...@globaleagleent.com
---
 libavformat/crypto.c | 233 ---
 libavformat/hlsenc.c | 387 ++-
 2 files changed, 567 insertions(+), 53 deletions(-)

diff --git a/libavformat/crypto.c b/libavformat/crypto.c
index a9b6e47..dc3dc88 100644
--- a/libavformat/crypto.c
+++ b/libavformat/crypto.c
@@ -38,17 +38,35 @@ typedef struct {
 int indata, indata_used, outdata;
 int eof;
 uint8_t *key;
-int keylen;
+int key_len;
 uint8_t *iv;
-int ivlen;
-struct AVAES *aes;
+int iv_len;
+uint8_t *decrypt_key;
+int decrypt_key_len;
+uint8_t *decrypt_iv;
+int decrypt_iv_len;
+uint8_t *encrypt_key;
+int encrypt_key_len;
+uint8_t *encrypt_iv;
+int encrypt_iv_len;
+struct AVAES *aes_decrypt;
+struct AVAES *aes_encrypt;
+
+uint8_t pad[BLOCKSIZE];
+int pad_len;
+
 } CryptoContext;
 
 #define OFFSET(x) offsetof(CryptoContext, x)
 #define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
-{key, AES decryption key, OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D 
},
-{iv,  AES decryption initialization vector, OFFSET(iv), 
AV_OPT_TYPE_BINARY, .flags = D },
+{key, AES encryption/decryption key,   OFFSET(key),
 AV_OPT_TYPE_BINARY, .flags = D|E },
+{iv,  AES encryption/decryption initialization vector, OFFSET(iv), 
 AV_OPT_TYPE_BINARY, .flags = D|E },
+{decryption_key, AES decryption key,   
OFFSET(decrypt_key), AV_OPT_TYPE_BINARY, .flags = D },
+{decryption_iv,  AES decryption initialization vector, 
OFFSET(decrypt_iv),  AV_OPT_TYPE_BINARY, .flags = D },
+{encryption_key, AES encryption key,   
OFFSET(encrypt_key), AV_OPT_TYPE_BINARY, .flags = E },
+{encryption_iv,  AES encryption initialization vector, 
OFFSET(encrypt_iv),  AV_OPT_TYPE_BINARY, .flags = E },
 { NULL }
 };
 
@@ -72,28 +90,145 @@ static int crypto_open2(URLContext *h, const char *uri, 
int flags, AVDictionary
 goto err;
 }
 
-if (c-keylen  BLOCKSIZE || c-ivlen  BLOCKSIZE) {
-av_log(h, AV_LOG_ERROR, Key or IV not set\n);
-ret = AVERROR(EINVAL);
-goto err;
+if (flags  AVIO_FLAG_READ) {
+if (!c-decrypt_key_len) {
+if (!c-key_len) {
+av_log(h, AV_LOG_ERROR, decryption key not set\n);
+ret = AVERROR(EINVAL);
+goto err;
+} else if (c-key_len != BLOCKSIZE) {
+av_log(h, AV_LOG_ERROR, invalid key size 
+(%d bytes, block size is %d)\n,
+c-key_len, BLOCKSIZE);
+ret = AVERROR(EINVAL);
+goto err;
+}
+c-decrypt_key = av_malloc(c-key_len);
+if (!c-decrypt_key) {
+ret = AVERROR(ENOMEM);
+goto err;
+}
+memcpy(c-decrypt_key, c-key, c-key_len);
+c-decrypt_key_len = c-key_len;
+} else if (c-decrypt_key_len != BLOCKSIZE) {
+av_log(h, AV_LOG_ERROR, invalid decryption key size 
+(%d bytes, block size is %d)\n,
+c-decrypt_key_len, BLOCKSIZE);
+ret = AVERROR(EINVAL);
+goto err;
+}
+if (!c-decrypt_iv_len) {
+if (!c-iv_len) {
+av_log(h, AV_LOG_ERROR, decryption IV not set\n);
+ret = AVERROR(EINVAL);
+goto err;
+} else if (c-iv_len != BLOCKSIZE) {
+av_log(h, AV_LOG_ERROR, invalid IV size 
+(%d bytes, block size is %d)\n,
+c-iv_len, BLOCKSIZE);
+ret = AVERROR(EINVAL);
+goto err;
+}
+c-decrypt_iv = av_malloc(c-iv_len);
+if (!c-decrypt_iv) {
+ret = AVERROR(ENOMEM);
+goto err;
+}
+memcpy(c-decrypt_iv, c-iv, c-iv_len);
+c-decrypt_iv_len = c-iv_len;
+} else if (c-decrypt_iv_len != BLOCKSIZE) {
+av_log(h, AV_LOG_ERROR, invalid decryption IV size 
+(%d bytes, block size is %d)\n,
+c-decrypt_iv_len, BLOCKSIZE);
+ret = AVERROR(EINVAL);
+goto err;
+}
 }
+
 if (flags  AVIO_FLAG_WRITE) {
-av_log(h, AV_LOG_ERROR, Only decryption is supported currently\n);
-ret = AVERROR(ENOSYS);
-goto err;
+if (!c-encrypt_key_len) {
+if (!c-key_len) {
+av_log(h, AV_LOG_ERROR, encryption key not set\n);
+ret = AVERROR(EINVAL);
+goto err;
+} else if (c-key_len != BLOCKSIZE