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 #include "nal.h"
28 
30 {
31  size_t new_alloc_size;
32 
33  if (ctx->auxiliary_info_size + size > ctx->auxiliary_info_alloc_size) {
34  new_alloc_size = FFMAX(ctx->auxiliary_info_size + size, ctx->auxiliary_info_alloc_size * 2);
35  if (av_reallocp(&ctx->auxiliary_info, new_alloc_size)) {
36  return AVERROR(ENOMEM);
37  }
38 
39  ctx->auxiliary_info_alloc_size = new_alloc_size;
40  }
41 
42  return 0;
43 }
44 
46  const uint8_t *buf_in, int size)
47 {
48  int ret;
49 
51  if (ret) {
52  return ret;
53  }
54  memcpy(ctx->auxiliary_info + ctx->auxiliary_info_size, buf_in, size);
55  ctx->auxiliary_info_size += size;
56 
57  return 0;
58 }
59 
61  uint16_t clear_bytes, uint32_t encrypted_bytes)
62 {
63  uint8_t* p;
64  int ret;
65 
66  if (!ctx->use_subsamples) {
67  return 0;
68  }
69 
71  if (ret) {
72  return ret;
73  }
74 
75  p = ctx->auxiliary_info + ctx->auxiliary_info_size;
76 
77  AV_WB16(p, clear_bytes);
78  p += sizeof(uint16_t);
79 
80  AV_WB32(p, encrypted_bytes);
81 
82  ctx->auxiliary_info_size += 6;
83  ctx->subsample_count++;
84 
85  return 0;
86 }
87 
88 /**
89  * Encrypt the input buffer and write using avio_write
90  */
92  const uint8_t *buf_in, int size)
93 {
94  uint8_t chunk[4096];
95  const uint8_t* cur_pos = buf_in;
96  int size_left = size;
97  int cur_size;
98 
99  while (size_left > 0) {
100  cur_size = FFMIN(size_left, sizeof(chunk));
101  av_aes_ctr_crypt(ctx->aes_ctr, chunk, cur_pos, cur_size);
102  avio_write(pb, chunk, cur_size);
103  cur_pos += cur_size;
104  size_left -= cur_size;
105  }
106 }
107 
108 /**
109  * Start writing a packet
110  */
112 {
113  int ret;
114 
115  /* write the iv */
117  if (ret) {
118  return ret;
119  }
120 
121  if (!ctx->use_subsamples) {
122  return 0;
123  }
124 
125  /* write a zero subsample count */
126  ctx->auxiliary_info_subsample_start = ctx->auxiliary_info_size;
127  ctx->subsample_count = 0;
128  ret = auxiliary_info_write(ctx, (uint8_t*)&ctx->subsample_count, sizeof(ctx->subsample_count));
129  if (ret) {
130  return ret;
131  }
132 
133  return 0;
134 }
135 
136 /**
137  * Finalize a packet
138  */
140 {
141  size_t new_alloc_size;
142 
143  av_aes_ctr_increment_iv(ctx->aes_ctr);
144 
145  if (!ctx->use_subsamples) {
146  ctx->auxiliary_info_entries++;
147  return 0;
148  }
149 
150  /* add the auxiliary info entry size*/
151  if (ctx->auxiliary_info_entries >= ctx->auxiliary_info_sizes_alloc_size) {
152  new_alloc_size = ctx->auxiliary_info_entries * 2 + 1;
153  if (av_reallocp(&ctx->auxiliary_info_sizes, new_alloc_size)) {
154  return AVERROR(ENOMEM);
155  }
156 
157  ctx->auxiliary_info_sizes_alloc_size = new_alloc_size;
158  }
159  ctx->auxiliary_info_sizes[ctx->auxiliary_info_entries] =
160  AES_CTR_IV_SIZE + ctx->auxiliary_info_size - ctx->auxiliary_info_subsample_start;
161  ctx->auxiliary_info_entries++;
162 
163  /* update the subsample count*/
164  AV_WB16(ctx->auxiliary_info + ctx->auxiliary_info_subsample_start, ctx->subsample_count);
165 
166  return 0;
167 }
168 
170  const uint8_t *buf_in, int size)
171 {
172  int ret;
173 
175  if (ret) {
176  return ret;
177  }
178 
180  if (ret) {
181  return ret;
182  }
183 
184  mov_cenc_write_encrypted(ctx, pb, buf_in, size);
185 
187  if (ret) {
188  return ret;
189  }
190 
191  return 0;
192 }
193 
195  const uint8_t *buf_in, int size)
196 {
197  const uint8_t *p = buf_in;
198  const uint8_t *end = p + size;
199  const uint8_t *nal_start, *nal_end;
200  int ret;
201 
203  if (ret) {
204  return ret;
205  }
206 
207  size = 0;
208  nal_start = ff_nal_find_startcode(p, end);
209  for (;;) {
210  while (nal_start < end && !*(nal_start++));
211  if (nal_start == end)
212  break;
213 
214  nal_end = ff_nal_find_startcode(nal_start, end);
215 
216  avio_wb32(pb, nal_end - nal_start);
217  avio_w8(pb, *nal_start);
218  mov_cenc_write_encrypted(ctx, pb, nal_start + 1, nal_end - nal_start - 1);
219 
220  auxiliary_info_add_subsample(ctx, 5, nal_end - nal_start - 1);
221 
222  size += 4 + nal_end - nal_start;
223  nal_start = nal_end;
224  }
225 
227  if (ret) {
228  return ret;
229  }
230 
231  return size;
232 }
233 
235  int nal_length_size, AVIOContext *pb, const uint8_t *buf_in, int size)
236 {
237  int nalsize;
238  int ret;
239  int j;
240 
242  if (ret) {
243  return ret;
244  }
245 
246  while (size > 0) {
247  /* parse the nal size */
248  if (size < nal_length_size + 1) {
249  av_log(s, AV_LOG_ERROR, "CENC-AVC: remaining size %d smaller than nal length+type %d\n",
250  size, nal_length_size + 1);
251  return -1;
252  }
253 
254  avio_write(pb, buf_in, nal_length_size + 1);
255 
256  nalsize = 0;
257  for (j = 0; j < nal_length_size; j++) {
258  nalsize = (nalsize << 8) | *buf_in++;
259  }
260  size -= nal_length_size;
261 
262  /* encrypt the nal body */
263  if (nalsize <= 0 || nalsize > size) {
264  av_log(s, AV_LOG_ERROR, "CENC-AVC: nal size %d remaining %d\n", nalsize, size);
265  return -1;
266  }
267 
268  mov_cenc_write_encrypted(ctx, pb, buf_in + 1, nalsize - 1);
269  buf_in += nalsize;
270  size -= nalsize;
271 
272  auxiliary_info_add_subsample(ctx, nal_length_size + 1, nalsize - 1);
273  }
274 
276  if (ret) {
277  return ret;
278  }
279 
280  return 0;
281 }
282 
283 /* TODO: reuse this function from movenc.c */
285 {
286  int64_t curpos = avio_tell(pb);
287  avio_seek(pb, pos, SEEK_SET);
288  avio_wb32(pb, curpos - pos); /* rewrite size */
289  avio_seek(pb, curpos, SEEK_SET);
290 
291  return curpos - pos;
292 }
293 
295  int64_t* auxiliary_info_offset)
296 {
297  int64_t pos = avio_tell(pb);
298 
299  avio_wb32(pb, 0); /* size */
300  ffio_wfourcc(pb, "senc");
301  avio_wb32(pb, ctx->use_subsamples ? 0x02 : 0); /* version & flags */
302  avio_wb32(pb, ctx->auxiliary_info_entries); /* entry count */
303  *auxiliary_info_offset = avio_tell(pb);
304  avio_write(pb, ctx->auxiliary_info, ctx->auxiliary_info_size);
305  return update_size(pb, pos);
306 }
307 
308 static int mov_cenc_write_saio_tag(AVIOContext *pb, int64_t auxiliary_info_offset)
309 {
310  int64_t pos = avio_tell(pb);
311  uint8_t version;
312 
313  avio_wb32(pb, 0); /* size */
314  ffio_wfourcc(pb, "saio");
315  version = auxiliary_info_offset > 0xffffffff ? 1 : 0;
316  avio_w8(pb, version);
317  avio_wb24(pb, 0); /* flags */
318  avio_wb32(pb, 1); /* entry count */
319  if (version) {
320  avio_wb64(pb, auxiliary_info_offset);
321  } else {
322  avio_wb32(pb, auxiliary_info_offset);
323  }
324  return update_size(pb, pos);
325 }
326 
328 {
329  int64_t pos = avio_tell(pb);
330  avio_wb32(pb, 0); /* size */
331  ffio_wfourcc(pb, "saiz");
332  avio_wb32(pb, 0); /* version & flags */
333  avio_w8(pb, ctx->use_subsamples ? 0 : AES_CTR_IV_SIZE); /* default size*/
334  avio_wb32(pb, ctx->auxiliary_info_entries); /* entry count */
335  if (ctx->use_subsamples) {
336  avio_write(pb, ctx->auxiliary_info_sizes, ctx->auxiliary_info_entries);
337  }
338  return update_size(pb, pos);
339 }
340 
342  int64_t moof_offset)
343 {
344  int64_t auxiliary_info_offset;
345 
346  mov_cenc_write_senc_tag(ctx, pb, &auxiliary_info_offset);
347  mov_cenc_write_saio_tag(pb, auxiliary_info_offset - moof_offset);
349 }
350 
351 static int mov_cenc_write_schi_tag(AVIOContext *pb, uint8_t* kid)
352 {
353  int64_t pos = avio_tell(pb);
354  avio_wb32(pb, 0); /* size */
355  ffio_wfourcc(pb, "schi");
356 
357  avio_wb32(pb, 32); /* size */
358  ffio_wfourcc(pb, "tenc");
359  avio_wb32(pb, 0); /* version & flags */
360  avio_wb24(pb, 1); /* is encrypted */
361  avio_w8(pb, AES_CTR_IV_SIZE); /* iv size */
362  avio_write(pb, kid, CENC_KID_SIZE);
363 
364  return update_size(pb, pos);
365 }
366 
367 int ff_mov_cenc_write_sinf_tag(MOVTrack* track, AVIOContext *pb, uint8_t* kid)
368 {
369  int64_t pos = avio_tell(pb);
370  avio_wb32(pb, 0); /* size */
371  ffio_wfourcc(pb, "sinf");
372 
373  /* frma */
374  avio_wb32(pb, 12); /* size */
375  ffio_wfourcc(pb, "frma");
376  avio_wl32(pb, track->tag);
377 
378  /* schm */
379  avio_wb32(pb, 20); /* size */
380  ffio_wfourcc(pb, "schm");
381  avio_wb32(pb, 0); /* version & flags */
382  ffio_wfourcc(pb, "cenc"); /* scheme type*/
383  avio_wb32(pb, 0x10000); /* scheme version */
384 
385  /* schi */
386  mov_cenc_write_schi_tag(pb, kid);
387 
388  return update_size(pb, pos);
389 }
390 
391 int ff_mov_cenc_init(MOVMuxCencContext* ctx, uint8_t* encryption_key,
392  int use_subsamples, int bitexact)
393 {
394  int ret;
395 
396  ctx->aes_ctr = av_aes_ctr_alloc();
397  if (!ctx->aes_ctr) {
398  return AVERROR(ENOMEM);
399  }
400 
401  ret = av_aes_ctr_init(ctx->aes_ctr, encryption_key);
402  if (ret != 0) {
403  return ret;
404  }
405 
406  if (!bitexact) {
407  av_aes_ctr_set_random_iv(ctx->aes_ctr);
408  }
409 
410  ctx->use_subsamples = use_subsamples;
411 
412  return 0;
413 }
414 
416 {
417  av_aes_ctr_free(ctx->aes_ctr);
418  av_freep(&ctx->auxiliary_info);
419  av_freep(&ctx->auxiliary_info_sizes);
420 }
mov_cenc_write_senc_tag
static int mov_cenc_write_senc_tag(MOVMuxCencContext *ctx, AVIOContext *pb, int64_t *auxiliary_info_offset)
Definition: movenccenc.c:294
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:308
auxiliary_info_alloc_size
static int auxiliary_info_alloc_size(MOVMuxCencContext *ctx, int size)
Definition: movenccenc.c:29
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:91
int64_t
long long int64_t
Definition: coverity.c:34
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:139
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:111
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:415
mov_cenc_write_schi_tag
static int mov_cenc_write_schi_tag(AVIOContext *pb, uint8_t *kid)
Definition: movenccenc.c:351
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
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:284
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:1300
AV_WB16
#define AV_WB16(p, v)
Definition: intreadwrite.h:401
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:234
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:391
movenc.h
AV_WB32
#define AV_WB32(p, v)
Definition: intreadwrite.h:415
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
ff_mov_cenc_write_stbl_atoms
void ff_mov_cenc_write_stbl_atoms(MOVMuxCencContext *ctx, AVIOContext *pb, int64_t moof_offset)
Write the cenc atoms that should reside inside stbl.
Definition: movenccenc.c:341
mov_cenc_write_saiz_tag
static int mov_cenc_write_saiz_tag(MOVMuxCencContext *ctx, AVIOContext *pb)
Definition: movenccenc.c:327
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:169
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
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:45
avio_internal.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
nal.h
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:367
auxiliary_info_add_subsample
static int auxiliary_info_add_subsample(MOVMuxCencContext *ctx, uint16_t clear_bytes, uint32_t encrypted_bytes)
Definition: movenccenc.c:60
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:194
ff_nal_find_startcode
const uint8_t * ff_nal_find_startcode(const uint8_t *p, const uint8_t *end)
Definition: nal.c:68