00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <string.h>
00023
00024 #include "libavutil/intreadwrite.h"
00025 #include "avformat.h"
00026 #include "internal.h"
00027 #include "oggdec.h"
00028
00029 struct oggopus_private {
00030 int need_comments;
00031 unsigned pre_skip;
00032 int64_t cur_dts;
00033 };
00034
00035 #define OPUS_HEAD_SIZE 19
00036
00037 static int opus_header(AVFormatContext *avf, int idx)
00038 {
00039 struct ogg *ogg = avf->priv_data;
00040 struct ogg_stream *os = &ogg->streams[idx];
00041 AVStream *st = avf->streams[idx];
00042 struct oggopus_private *priv = os->private;
00043 uint8_t *packet = os->buf + os->pstart;
00044 uint8_t *extradata;
00045
00046 if (!priv) {
00047 priv = os->private = av_mallocz(sizeof(*priv));
00048 if (!priv)
00049 return AVERROR(ENOMEM);
00050 }
00051 if (os->flags & OGG_FLAG_BOS) {
00052 if (os->psize < OPUS_HEAD_SIZE || (AV_RL8(packet + 8) & 0xF0) != 0)
00053 return AVERROR_INVALIDDATA;
00054 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00055 st->codec->codec_id = AV_CODEC_ID_OPUS;
00056 st->codec->channels = AV_RL8 (packet + 9);
00057 priv->pre_skip = AV_RL16(packet + 10);
00058
00059
00060
00061
00062 extradata = av_malloc(os->psize + FF_INPUT_BUFFER_PADDING_SIZE);
00063 if (!extradata)
00064 return AVERROR(ENOMEM);
00065 memcpy(extradata, packet, os->psize);
00066 st->codec->extradata = extradata;
00067 st->codec->extradata_size = os->psize;
00068
00069 st->codec->sample_rate = 48000;
00070 avpriv_set_pts_info(st, 64, 1, 48000);
00071 priv->need_comments = 1;
00072 return 1;
00073 }
00074
00075 if (priv->need_comments) {
00076 if (os->psize < 8 || memcmp(packet, "OpusTags", 8))
00077 return AVERROR_INVALIDDATA;
00078 ff_vorbis_comment(avf, &st->metadata, packet + 8, os->psize - 8);
00079 priv->need_comments--;
00080 return 1;
00081 }
00082 return 0;
00083 }
00084
00085 static int opus_packet(AVFormatContext *avf, int idx)
00086 {
00087 struct ogg *ogg = avf->priv_data;
00088 struct ogg_stream *os = &ogg->streams[idx];
00089 AVStream *st = avf->streams[idx];
00090 struct oggopus_private *priv = os->private;
00091 uint8_t *packet = os->buf + os->pstart;
00092 unsigned toc, toc_config, toc_count, frame_size, nb_frames = 1;
00093
00094 if (!os->psize)
00095 return AVERROR_INVALIDDATA;
00096 toc = *packet;
00097 toc_config = toc >> 3;
00098 toc_count = toc & 3;
00099 frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
00100 toc_config < 16 ? 480 << (toc_config & 1) :
00101 120 << (toc_config & 3);
00102 if (toc_count == 3) {
00103 if (os->psize < 2)
00104 return AVERROR_INVALIDDATA;
00105 nb_frames = packet[1] & 0x3F;
00106 } else if (toc_count) {
00107 nb_frames = 2;
00108 }
00109 os->pduration = frame_size * nb_frames;
00110 if (os->lastpts != AV_NOPTS_VALUE) {
00111 if (st->start_time == AV_NOPTS_VALUE)
00112 st->start_time = os->lastpts;
00113 priv->cur_dts = os->lastdts = os->lastpts -= priv->pre_skip;
00114 }
00115 priv->cur_dts += os->pduration;
00116 if ((os->flags & OGG_FLAG_EOS)) {
00117 int64_t skip = priv->cur_dts - os->granule + priv->pre_skip;
00118 skip = FFMIN(skip, os->pduration);
00119 if (skip > 0) {
00120 os->pduration = skip < os->pduration ? os->pduration - skip : 1;
00121 av_log(avf, AV_LOG_WARNING,
00122 "Last packet must be truncated to %d (unimplemented).\n",
00123 os->pduration);
00124 }
00125 }
00126 return 0;
00127 }
00128
00129 const struct ogg_codec ff_opus_codec = {
00130 .name = "Opus",
00131 .magic = "OpusHead",
00132 .magicsize = 8,
00133 .header = opus_header,
00134 .packet = opus_packet,
00135 };