FFmpeg
movenccenc.c
Go to the documentation of this file.
1 /*
2  * MOV CENC (Common Encryption) writer
3  * Copyright (c) 2015 Eran Kornblau <erankor at gmail dot com>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 #include "movenccenc.h"
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/mem.h"
24 #include "avio_internal.h"
25 #include "movenc.h"
26 #include "avc.h"
27 
29 {
30  size_t new_alloc_size;
31 
32  if (ctx->auxiliary_info_size + size > ctx->auxiliary_info_alloc_size) {
33  new_alloc_size = FFMAX(ctx->auxiliary_info_size + size, ctx->auxiliary_info_alloc_size * 2);
34  if (av_reallocp(&ctx->auxiliary_info, new_alloc_size)) {
35  return AVERROR(ENOMEM);
36  }
37 
38  ctx->auxiliary_info_alloc_size = new_alloc_size;
39  }
40 
41  return 0;
42 }
43 
45  const uint8_t *buf_in, int size)
46 {
47  int ret;
48 
50  if (ret) {
51  return ret;
52  }
53  memcpy(ctx->auxiliary_info + ctx->auxiliary_info_size, buf_in, size);
54  ctx->auxiliary_info_size += size;
55 
56  return 0;
57 }
58 
60  uint16_t clear_bytes, uint32_t encrypted_bytes)
61 {
62  uint8_t* p;
63  int ret;
64 
65  if (!ctx->use_subsamples) {
66  return 0;
67  }
68 
70  if (ret) {
71  return ret;
72  }
73 
74  p = ctx->auxiliary_info + ctx->auxiliary_info_size;
75 
76  AV_WB16(p, clear_bytes);
77  p += sizeof(uint16_t);
78 
79  AV_WB32(p, encrypted_bytes);
80 
81  ctx->auxiliary_info_size += 6;
82  ctx->subsample_count++;
83 
84  return 0;
85 }
86 
87 /**
88  * Encrypt the input buffer and write using avio_write
89  */
91  const uint8_t *buf_in, int size)
92 {
93  uint8_t chunk[4096];
94  const uint8_t* cur_pos = buf_in;
95  int size_left = size;
96  int cur_size;
97 
98  while (size_left > 0) {
99  cur_size = FFMIN(size_left, sizeof(chunk));
100  av_aes_ctr_crypt(ctx->aes_ctr, chunk, cur_pos, cur_size);
101  avio_write(pb, chunk, cur_size);
102  cur_pos += cur_size;
103  size_left -= cur_size;
104  }
105 }
106 
107 /**
108  * Start writing a packet
109  */
111 {
112  int ret;
113 
114  /* write the iv */
116  if (ret) {
117  return ret;
118  }
119 
120  if (!ctx->use_subsamples) {
121  return 0;
122  }
123 
124  /* write a zero subsample count */
125  ctx->auxiliary_info_subsample_start = ctx->auxiliary_info_size;
126  ctx->subsample_count = 0;
127  ret = auxiliary_info_write(ctx, (uint8_t*)&ctx->subsample_count, sizeof(ctx->subsample_count));
128  if (ret) {
129  return ret;
130  }
131 
132  return 0;
133 }
134 
135 /**
136  * Finalize a packet
137  */
139 {
140  size_t new_alloc_size;
141 
142  av_aes_ctr_increment_iv(ctx->aes_ctr);
143 
144  if (!ctx->use_subsamples) {
145  ctx->auxiliary_info_entries++;
146  return 0;
147  }
148 
149  /* add the auxiliary info entry size*/
150  if (ctx->auxiliary_info_entries >= ctx->auxiliary_info_sizes_alloc_size) {
151  new_alloc_size = ctx->auxiliary_info_entries * 2 + 1;
152  if (av_reallocp(&ctx->auxiliary_info_sizes, new_alloc_size)) {
153  return AVERROR(ENOMEM);
154  }
155 
156  ctx->auxiliary_info_sizes_alloc_size = new_alloc_size;
157  }
158  ctx->auxiliary_info_sizes[ctx->auxiliary_info_entries] =
159  AES_CTR_IV_SIZE + ctx->auxiliary_info_size - ctx->auxiliary_info_subsample_start;
160  ctx->auxiliary_info_entries++;
161 
162  /* update the subsample count*/
163  AV_WB16(ctx->auxiliary_info + ctx->auxiliary_info_subsample_start, ctx->subsample_count);
164 
165  return 0;
166 }
167 
169  const uint8_t *buf_in, int size)
170 {
171  int ret;
172 
174  if (ret) {
175  return ret;
176  }
177 
179  if (ret) {
180  return ret;
181  }
182 
183  mov_cenc_write_encrypted(ctx, pb, buf_in, size);
184 
186  if (ret) {
187  return ret;
188  }
189 
190  return 0;
191 }
192 
194  const uint8_t *buf_in, int size)
195 {
196  const uint8_t *p = buf_in;
197  const uint8_t *end = p + size;
198  const uint8_t *nal_start, *nal_end;
199  int ret;
200 
202  if (ret) {
203  return ret;
204  }
205 
206  size = 0;
207  nal_start = ff_avc_find_startcode(p, end);
208  for (;;) {
209  while (nal_start < end && !*(nal_start++));
210  if (nal_start == end)
211  break;
212 
213  nal_end = ff_avc_find_startcode(nal_start, end);
214 
215  avio_wb32(pb, nal_end - nal_start);
216  avio_w8(pb, *nal_start);
217  mov_cenc_write_encrypted(ctx, pb, nal_start + 1, nal_end - nal_start - 1);
218 
219  auxiliary_info_add_subsample(ctx, 5, nal_end - nal_start - 1);
220 
221  size += 4 + nal_end - nal_start;
222  nal_start = nal_end;
223  }
224 
226  if (ret) {
227  return ret;
228  }
229 
230  return size;
231 }
232 
234  int nal_length_size, AVIOContext *pb, const uint8_t *buf_in, int size)
235 {
236  int nalsize;
237  int ret;
238  int j;
239 
241  if (ret) {
242  return ret;
243  }
244 
245  while (size > 0) {
246  /* parse the nal size */
247  if (size < nal_length_size + 1) {
248  av_log(s, AV_LOG_ERROR, "CENC-AVC: remaining size %d smaller than nal length+type %d\n",
249  size, nal_length_size + 1);
250  return -1;
251  }
252 
253  avio_write(pb, buf_in, nal_length_size + 1);
254 
255  nalsize = 0;
256  for (j = 0; j < nal_length_size; j++) {
257  nalsize = (nalsize << 8) | *buf_in++;
258  }
259  size -= nal_length_size;
260 
261  /* encrypt the nal body */
262  if (nalsize <= 0 || nalsize > size) {
263  av_log(s, AV_LOG_ERROR, "CENC-AVC: nal size %d remaining %d\n", nalsize, size);
264  return -1;
265  }
266 
267  mov_cenc_write_encrypted(ctx, pb, buf_in + 1, nalsize - 1);
268  buf_in += nalsize;
269  size -= nalsize;
270 
271  auxiliary_info_add_subsample(ctx, nal_length_size + 1, nalsize - 1);
272  }
273 
275  if (ret) {
276  return ret;
277  }
278 
279  return 0;
280 }
281 
282 /* TODO: reuse this function from movenc.c */
283 static int64_t update_size(AVIOContext *pb, int64_t pos)
284 {
285  int64_t curpos = avio_tell(pb);
286  avio_seek(pb, pos, SEEK_SET);
287  avio_wb32(pb, curpos - pos); /* rewrite size */
288  avio_seek(pb, curpos, SEEK_SET);
289 
290  return curpos - pos;
291 }
292 
294  int64_t* auxiliary_info_offset)
295 {
296  int64_t pos = avio_tell(pb);
297 
298  avio_wb32(pb, 0); /* size */
299  ffio_wfourcc(pb, "senc");
300  avio_wb32(pb, ctx->use_subsamples ? 0x02 : 0); /* version & flags */
301  avio_wb32(pb, ctx->auxiliary_info_entries); /* entry count */
302  *auxiliary_info_offset = avio_tell(pb);
303  avio_write(pb, ctx->auxiliary_info, ctx->auxiliary_info_size);
304  return update_size(pb, pos);
305 }
306 
307 static int mov_cenc_write_saio_tag(AVIOContext *pb, int64_t auxiliary_info_offset)
308 {
309  int64_t pos = avio_tell(pb);
310  uint8_t version;
311 
312  avio_wb32(pb, 0); /* size */
313  ffio_wfourcc(pb, "saio");
314  version = auxiliary_info_offset > 0xffffffff ? 1 : 0;
315  avio_w8(pb, version);
316  avio_wb24(pb, 0); /* flags */
317  avio_wb32(pb, 1); /* entry count */
318  if (version) {
319  avio_wb64(pb, auxiliary_info_offset);
320  } else {
321  avio_wb32(pb, auxiliary_info_offset);
322  }
323  return update_size(pb, pos);
324 }
325 
327 {
328  int64_t pos = avio_tell(pb);
329  avio_wb32(pb, 0); /* size */
330  ffio_wfourcc(pb, "saiz");
331  avio_wb32(pb, 0); /* version & flags */
332  avio_w8(pb, ctx->use_subsamples ? 0 : AES_CTR_IV_SIZE); /* default size*/
333  avio_wb32(pb, ctx->auxiliary_info_entries); /* entry count */
334  if (ctx->use_subsamples) {
335  avio_write(pb, ctx->auxiliary_info_sizes, ctx->auxiliary_info_entries);
336  }
337  return update_size(pb, pos);
338 }
339 
341 {
342  int64_t auxiliary_info_offset;
343 
344  mov_cenc_write_senc_tag(ctx, pb, &auxiliary_info_offset);
345  mov_cenc_write_saio_tag(pb, auxiliary_info_offset);
347 }
348 
349 static int mov_cenc_write_schi_tag(AVIOContext *pb, uint8_t* kid)
350 {
351  int64_t pos = avio_tell(pb);
352  avio_wb32(pb, 0); /* size */
353  ffio_wfourcc(pb, "schi");
354 
355  avio_wb32(pb, 32); /* size */
356  ffio_wfourcc(pb, "tenc");
357  avio_wb32(pb, 0); /* version & flags */
358  avio_wb24(pb, 1); /* is encrypted */
359  avio_w8(pb, AES_CTR_IV_SIZE); /* iv size */
360  avio_write(pb, kid, CENC_KID_SIZE);
361 
362  return update_size(pb, pos);
363 }
364 
365 int ff_mov_cenc_write_sinf_tag(MOVTrack* track, AVIOContext *pb, uint8_t* kid)
366 {
367  int64_t pos = avio_tell(pb);
368  avio_wb32(pb, 0); /* size */
369  ffio_wfourcc(pb, "sinf");
370 
371  /* frma */
372  avio_wb32(pb, 12); /* size */
373  ffio_wfourcc(pb, "frma");
374  avio_wl32(pb, track->tag);
375 
376  /* schm */
377  avio_wb32(pb, 20); /* size */
378  ffio_wfourcc(pb, "schm");
379  avio_wb32(pb, 0); /* version & flags */
380  ffio_wfourcc(pb, "cenc"); /* scheme type*/
381  avio_wb32(pb, 0x10000); /* scheme version */
382 
383  /* schi */
384  mov_cenc_write_schi_tag(pb, kid);
385 
386  return update_size(pb, pos);
387 }
388 
389 int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
390  int use_subsamples, int bitexact)
391 {
392  int ret;
393 
394  ctx->aes_ctr = av_aes_ctr_alloc();
395  if (!ctx->aes_ctr) {
396  return AVERROR(ENOMEM);
397  }
398 
399  ret = av_aes_ctr_init(ctx->aes_ctr, encryption_key);
400  if (ret != 0) {
401  return ret;
402  }
403 
404  if (!bitexact) {
405  av_aes_ctr_set_random_iv(ctx->aes_ctr);
406  }
407 
408  ctx->use_subsamples = use_subsamples;
409 
410  return 0;
411 }
412 
414 {
415  av_aes_ctr_free(ctx->aes_ctr);
416  av_freep(&ctx->auxiliary_info);
417  av_freep(&ctx->auxiliary_info_sizes);
418 }
mov_cenc_write_senc_tag
static int mov_cenc_write_senc_tag(MOVMuxCencContext *ctx, AVIOContext *pb, int64_t *auxiliary_info_offset)
Definition: movenccenc.c:293
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
ffio_wfourcc
static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
Definition: avio_internal.h:124
mov_cenc_write_saio_tag
static int mov_cenc_write_saio_tag(AVIOContext *pb, int64_t auxiliary_info_offset)
Definition: movenccenc.c:307
auxiliary_info_alloc_size
static int auxiliary_info_alloc_size(MOVMuxCencContext *ctx, int size)
Definition: movenccenc.c:28
mov_cenc_write_encrypted
static void mov_cenc_write_encrypted(MOVMuxCencContext *ctx, AVIOContext *pb, const uint8_t *buf_in, int size)
Encrypt the input buffer and write using avio_write.
Definition: movenccenc.c:90
MOVTrack::tag
int tag
stsd fourcc
Definition: movenc.h:108
mov_cenc_end_packet
static int mov_cenc_end_packet(MOVMuxCencContext *ctx)
Finalize a packet.
Definition: movenccenc.c:138
av_aes_ctr_set_random_iv
void av_aes_ctr_set_random_iv(struct AVAESCTR *a)
Generate a random iv.
Definition: aes_ctr.c:63
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
mov_cenc_start_packet
static int mov_cenc_start_packet(MOVMuxCencContext *ctx)
Start writing a packet.
Definition: movenccenc.c:110
MOVTrack
Definition: movenc.h:86
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
CENC_KID_SIZE
#define CENC_KID_SIZE
Definition: movenccenc.h:29
ff_mov_cenc_free
void ff_mov_cenc_free(MOVMuxCencContext *ctx)
Free a CENC context.
Definition: movenccenc.c:413
mov_cenc_write_schi_tag
static int mov_cenc_write_schi_tag(AVIOContext *pb, uint8_t *kid)
Definition: movenccenc.c:349
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
movenccenc.h
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
update_size
static int64_t update_size(AVIOContext *pb, int64_t pos)
Definition: movenccenc.c:283
ctx
AVFormatContext * ctx
Definition: movenc.c:49
av_aes_ctr_get_iv
const uint8_t * av_aes_ctr_get_iv(struct AVAESCTR *a)
Get the current iv.
Definition: aes_ctr.c:58
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
AV_WB16
#define AV_WB16(p, v)
Definition: intreadwrite.h:403
av_aes_ctr_alloc
struct AVAESCTR * av_aes_ctr_alloc(void)
Allocate an AVAESCTR context.
Definition: aes_ctr.c:40
ff_mov_cenc_avc_write_nal_units
int ff_mov_cenc_avc_write_nal_units(AVFormatContext *s, MOVMuxCencContext *ctx, int nal_length_size, AVIOContext *pb, const uint8_t *buf_in, int size)
Write AVC NAL units that are in MP4 format, the nal size and type are written in the clear while the ...
Definition: movenccenc.c:233
avc.h
avio_w8
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:179
ff_mov_cenc_init
int ff_mov_cenc_init(MOVMuxCencContext *ctx, uint8_t *encryption_key, int use_subsamples, int bitexact)
Initialize a CENC context.
Definition: movenccenc.c:389
movenc.h
AV_WB32
#define AV_WB32(p, v)
Definition: intreadwrite.h:417
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
av_aes_ctr_init
int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key)
Initialize an AVAESCTR context.
Definition: aes_ctr.c:73
mov_cenc_write_saiz_tag
static int mov_cenc_write_saiz_tag(MOVMuxCencContext *ctx, AVIOContext *pb)
Definition: movenccenc.c:326
ff_mov_cenc_write_packet
int ff_mov_cenc_write_packet(MOVMuxCencContext *ctx, AVIOContext *pb, const uint8_t *buf_in, int size)
Write a fully encrypted packet.
Definition: movenccenc.c:168
size
int size
Definition: twinvq_data.h:10344
av_reallocp
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:188
avio_write
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:201
avio_wb32
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:365
avio_wl32
void avio_wl32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:357
ff_mov_cenc_write_stbl_atoms
void ff_mov_cenc_write_stbl_atoms(MOVMuxCencContext *ctx, AVIOContext *pb)
Write the cenc atoms that should reside inside stbl.
Definition: movenccenc.c:340
version
version
Definition: libkvazaar.c:321
av_aes_ctr_free
void av_aes_ctr_free(struct AVAESCTR *a)
Release an AVAESCTR context.
Definition: aes_ctr.c:83
auxiliary_info_write
static int auxiliary_info_write(MOVMuxCencContext *ctx, const uint8_t *buf_in, int size)
Definition: movenccenc.c:44
avio_internal.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
ret
ret
Definition: filter_design.txt:187
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:231
ff_mov_cenc_write_sinf_tag
int ff_mov_cenc_write_sinf_tag(MOVTrack *track, AVIOContext *pb, uint8_t *kid)
Write the sinf atom, contained inside stsd.
Definition: movenccenc.c:365
auxiliary_info_add_subsample
static int auxiliary_info_add_subsample(MOVMuxCencContext *ctx, uint16_t clear_bytes, uint32_t encrypted_bytes)
Definition: movenccenc.c:59
pos
unsigned int pos
Definition: spdifenc.c:414
av_aes_ctr_increment_iv
void av_aes_ctr_increment_iv(struct AVAESCTR *a)
Increment the top 64 bit of the iv (performed after each frame)
Definition: aes_ctr.c:100
av_aes_ctr_crypt
void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int count)
Process a buffer using a previously initialized context.
Definition: aes_ctr.c:107
avio_wb64
void avio_wb64(AVIOContext *s, uint64_t val)
Definition: aviobuf.c:431
mem.h
MOVMuxCencContext
Definition: movenccenc.h:33
avio_wb24
void avio_wb24(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:455
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AES_CTR_IV_SIZE
#define AES_CTR_IV_SIZE
Definition: aes_ctr.h:36
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ff_mov_cenc_avc_parse_nal_units
int ff_mov_cenc_avc_parse_nal_units(MOVMuxCencContext *ctx, AVIOContext *pb, const uint8_t *buf_in, int size)
Parse AVC NAL units from annex B format, the nal size and type are written in the clear while the bod...
Definition: movenccenc.c:193
ff_avc_find_startcode
const uint8_t * ff_avc_find_startcode(const uint8_t *p, const uint8_t *end)
Definition: avc.c:67