@@ -219,6 +219,47 @@ fail:
return ret;
}
+int ff_avc_extract_parameter_sets(const uint8_t *buf_in, int size_in,
+ uint8_t **buf_out, int *size_out)
+{
+ const uint8_t *p = buf_in;
+ const uint8_t *end = p + size_in;
+ const uint8_t *nal_start, *nal_end;
+ AVIOContext *pb;
+ int ret = avio_open_dyn_buf(&pb);
+ if (ret < 0)
+ return ret;
+
+ nal_start = ff_avc_find_startcode(p, end);
+ for (;;) {
+ uint8_t nal_type;
+
+ while (nal_start < end && !*(nal_start++));
+ if (nal_start == end)
+ break;
+
+ nal_type = nal_start[0] & 0x1f;
+ nal_end = ff_avc_find_startcode(nal_start, end);
+
+ switch (nal_type) {
+ case 7: /* SPS */
+ case 8: /* PPS */
+ case 13: /* SPS_EXT */
+ avio_wb32(pb, 1);
+ avio_write(pb, nal_start, nal_end - nal_start);
+ break;
+ default:
+ break;
+ }
+
+ nal_start = nal_end;
+ }
+
+ *size_out = avio_close_dyn_buf(pb, buf_out);
+
+ return 0;
+}
+
int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)
{
uint16_t sps_size, pps_size;
@@ -36,6 +36,9 @@ const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start,
uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
uint32_t *dst_len, int header_len);
+int ff_avc_extract_parameter_sets(const uint8_t *buf_in, int size_in,
+ uint8_t **buf_out, int *size_out);
+
typedef struct {
uint8_t id;
uint8_t profile_idc;
@@ -1065,20 +1065,22 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out,
return 0;
}
-int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
- int size, int ps_array_completeness)
+static int write_parameter_sets(AVIOContext *pb, const uint8_t *data,
+ int size, int ps_array_completeness,
+ int write_hvcc)
{
int ret = 0;
uint8_t *buf, *end, *start = NULL;
HEVCDecoderConfigurationRecord hvcc;
- hvcc_init(&hvcc);
+ if (write_hvcc)
+ hvcc_init(&hvcc);
if (size < 6) {
/* We can't write a valid hvcC from the provided data */
ret = AVERROR_INVALIDDATA;
goto end;
- } else if (*data == 1) {
+ } else if (*data == 1 && write_hvcc) {
/* Data is already hvcC-formatted */
avio_write(pb, data, size);
goto end;
@@ -1107,9 +1109,14 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
case HEVC_NAL_PPS:
case HEVC_NAL_SEI_PREFIX:
case HEVC_NAL_SEI_SUFFIX:
- ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc);
- if (ret < 0)
- goto end;
+ if (write_hvcc) {
+ ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc);
+ if (ret < 0)
+ goto end;
+ } else {
+ avio_wb32(pb, 1);
+ avio_write(pb, buf, len);
+ }
break;
default:
break;
@@ -1118,10 +1125,37 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
buf += len;
}
- ret = hvcc_write(pb, &hvcc);
+ if (write_hvcc)
+ ret = hvcc_write(pb, &hvcc);
end:
- hvcc_close(&hvcc);
+ if (write_hvcc)
+ hvcc_close(&hvcc);
av_free(start);
return ret;
}
+
+int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
+ int size, int ps_array_completeness)
+{
+ return write_parameter_sets(pb, data, size, ps_array_completeness, 1);
+}
+
+int ff_hevc_extract_parameter_sets(const uint8_t *buf_in, int size_in,
+ uint8_t **buf_out, int *size_out)
+{
+ AVIOContext *pb;
+ int ret = avio_open_dyn_buf(&pb);
+ if (ret < 0)
+ return ret;
+
+ ret = write_parameter_sets(pb, buf_in, size_in, 0, 0);
+
+ *size_out = avio_close_dyn_buf(pb, buf_out);
+ if (ret < 0) {
+ av_freep(buf_out);
+ *size_out = 0;
+ }
+
+ return ret;
+}
@@ -96,4 +96,20 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out,
int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
int size, int ps_array_completeness);
+/**
+ * Extract the NAL units that belong to extradata from a full frame in
+ * Annex B format, storing them in a newly allocated buffer in Annex B
+ * format.
+ *
+ * @param buf_in pointer to the buffer holding the frame
+ * @param size_in size (in bytes) of the buf_in buffer
+ * @param buf_out pointer to a pointer where the allocated output buffer is
+ * stored
+ * @param size_out pointer where the size of buf_out is stored
+ * @return >=0 in case of success, a negative value corresponding to an AVERROR
+ * code in case of failure
+ */
+int ff_hevc_extract_parameter_sets(const uint8_t *buf_in, int size_in,
+ uint8_t **buf_out, int *size_out);
+
#endif /* AVFORMAT_HEVC_H */
@@ -5503,6 +5503,17 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(trk->vos_data, par->extradata, trk->vos_len);
memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
}
+ if (trk->vos_len == 0 && par->codec_id == AV_CODEC_ID_H264) {
+ ret = ff_avc_extract_parameter_sets(pkt->data, pkt->size,
+ &trk->vos_data, &trk->vos_len);
+ if (ret < 0)
+ goto err;
+ } else if (trk->vos_len == 0 && par->codec_id == AV_CODEC_ID_HEVC) {
+ ret = ff_hevc_extract_parameter_sets(pkt->data, pkt->size,
+ &trk->vos_data, &trk->vos_len);
+ if (ret < 0)
+ goto err;
+ }
if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
(AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {