From patchwork Thu May 28 10:34:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: A G X-Patchwork-Id: 19925 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 2B9A044B936 for ; Thu, 28 May 2020 13:34:47 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id F34E868AB24; Thu, 28 May 2020 13:34:46 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from NAM10-MW2-obe.outbound.protection.outlook.com (mail-mw2nam10olkn2095.outbound.protection.outlook.com [40.92.42.95]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0561468A9DB for ; Thu, 28 May 2020 13:34:39 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=TXJ8Z1KicfyJtbxFqw6ani3BiMw6nH/Ahbb/dDyW1Sv32FgmZB/yZhqcHtZxk4tZ8v9U0aevjPACrqU/rhEmBSvZWNrCGlX3uwWZaFyHSRuX1XVGkDfjAHCOIc9JXu9ConSEZdMJeJwcXiDAZcx1edgT9fQLrW8H+adPELfAdx+5Evg0wLvLnuE3OBq+9Pi11FQpo1lY3Sa439NtZ5hiO9HKOiC05bQqZNa2raIA5Zb5PziU9HIeP56slR+nM5NPdI2HJ2UII+SOAl+xVNs+KnLJpsRAkYxyHCSQpeInZhxSWrGRP+J3254fhAa4DsuKhP7vVQ6mfw+2bhcmeaCjSg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=N0aKcIKZfs4eHrZ3R7LWT0pO2Vep9LhwJeb+tEaPnCw=; b=F/o+7v7ailpFoXi//gIcpFLIQ7otZC0CHQtRHKi9W2Gd5S+Xbe0c9PfNn5+aTn0hq/lSnCRqUYnIqa1pcI0O0OxC7my+1BsweMhVvuWmclP2iD3x5frV+znU7h9XObDiBUGBnwmAmmkfO+tBbuGBswoKxja95Oxu1Gnucj7T2jxXEHIzvoXiNb5g+a3dkUEwP/n2XLH9hk7VNMf9UN4pFE7vNPcklqwvKfI3A5qX/ccKqQDu0C5TgXkjBnzy8ccDvWIr2Pg2oaoUnIcRJwueLIQoLg8Qv9oAJNb52P+/I1NuxvYx+QeS89M8wQVKg1z+ETAL872MKPbUxIjF/mqHRw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=N0aKcIKZfs4eHrZ3R7LWT0pO2Vep9LhwJeb+tEaPnCw=; b=RYbHJeEX8ENXsjkAaIX3hnJ72FQNkXMn0QYgVszKKdAgaySdT4TphYb58EiccoMSv2EMAfXoD3GPkladMe2fGoVJOZWqUFk9CLwQDtg9Q6kkvASXdsk7f9WCvDz1+E5T+EnkQx5n1pnYjEY/cdl2zbAKrXov7ajVv2qVUWtyOm9fX1+bHlKjxIAY374r+N2dMBrumVLkkil3XD+Vf3moYXq+rREbTVp6WYHX1oH+cNIE6oITmrXU9Bb8PxBk69FTCgGHt4B10xT8LwmKyRjKYlOy6+FdKgvYIu2YbZm4CcYDju0sdbHaI7Y/xTJnMdvl1dq9JWODGCI9GE1bOy6DPA== Received: from MW2NAM10FT064.eop-nam10.prod.protection.outlook.com (2a01:111:e400:7e87::43) by MW2NAM10HT118.eop-nam10.prod.protection.outlook.com (2a01:111:e400:7e87::405) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3021.23; Thu, 28 May 2020 10:34:37 +0000 Received: from BYAPR15MB2647.namprd15.prod.outlook.com (2a01:111:e400:7e87::4b) by MW2NAM10FT064.mail.protection.outlook.com (2a01:111:e400:7e87::101) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3021.23 via Frontend Transport; Thu, 28 May 2020 10:34:37 +0000 Received: from BYAPR15MB2647.namprd15.prod.outlook.com ([fe80::f083:ed57:da58:e2a1]) by BYAPR15MB2647.namprd15.prod.outlook.com ([fe80::f083:ed57:da58:e2a1%6]) with mapi id 15.20.3021.030; Thu, 28 May 2020 10:34:37 +0000 From: A G To: FFmpeg development discussions and patches Thread-Topic: [PATCH v2] avformat/oggenc: Add partial support for OggPCM muxing Thread-Index: AQHWNNnnq7SHnGRKDUuYe2/sirWhcA== Date: Thu, 28 May 2020 10:34:36 +0000 Message-ID: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-incomingtopheadermarker: OriginalChecksum:08E4360F61A93BEE88EEAC5A3C575B897BA525A22F545E81A04BDB38F5A534C3; UpperCasedChecksum:77E8C85822ED347240C9DDCF4D696E535F40E02750FFD4C000F1BD1C1323F150; SizeAsReceived:6784; Count:42 x-tmn: [SfvW5r03iFIf6I8rFfG9q1RpepOx7czU1xgp6GLVNwE=] x-ms-publictraffictype: Email x-incomingheadercount: 42 x-eopattributedmessage: 0 x-ms-office365-filtering-correlation-id: 45daf63f-bde2-4782-cc5d-08d802f2b852 x-ms-traffictypediagnostic: MW2NAM10HT118: x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: BCaYq4YWhH4BnaktMQqViQ6lZvquZIjhoOSAkFieZ/Kgl2BSwkqcITjCRY+7dXAL2lKPyDoFFjlioCmZcqw9ROvyAquSnp564bUFUfFwtR1tnPvim4BC466MVv9gVsYKn38nu1gfbCK9OdEAxk46b/3eJxqrzZBK9JsizyOqgjyoxmSSnO44VuPtNARc1rymfhLzQHCeZ2U47ecq0MA3n7UyUIGYlu/RZ2jWHHbC9IiBsWjHRsPxKUEG7XxwPg/f x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:0; SRV:; IPV:NLI; SFV:NSPM; H:BYAPR15MB2647.namprd15.prod.outlook.com; PTR:; CAT:NONE; SFTY:; SFS:; DIR:OUT; SFP:1901; x-ms-exchange-antispam-messagedata: vqjJD3Cj93juMD2eLQCm9zRaMmzeXrTCIYFoHujgUJTJyYASnzJVJ/BTo8Y7k5jIXInjVYH7vYj1/J4e8CRFC09aMYGbs3TpF+D/IvxZxuuYNXoFIl9gyEdeWy2zGHWXq+sZxyVlUv5ccrGpIpi+WxPOvTqSAQ9IGeicOUgDI9w= x-ms-exchange-transport-forked: True MIME-Version: 1.0 X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-CrossTenant-Network-Message-Id: 45daf63f-bde2-4782-cc5d-08d802f2b852 X-MS-Exchange-CrossTenant-rms-persistedconsumerorg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-CrossTenant-originalarrivaltime: 28 May 2020 10:34:37.0360 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Internet X-MS-Exchange-CrossTenant-id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW2NAM10HT118 X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: [FFmpeg-devel] [PATCH v2] avformat/oggenc: Add partial support for OggPCM muxing X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This adds partial support for OggPCM muxing. Heavily based on the work here: https://ffmpeg.org/pipermail/ffmpeg-devel/2013-July/145556.html and here: http://www.on2.com/media/gpl/mplayer/ --- libavformat/oggenc.c | 86 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) -- 2.26.2 diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index f5032759a6..153f7f6760 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -99,6 +99,36 @@ static const AVClass flavor ## _muxer_class = {\ .version = LIBAVUTIL_VERSION_INT,\ }; + +static const struct ogg_pcm_codec { + uint32_t codec_id; + uint32_t format_id; +} ogg_pcm_codecs[] = { + { AV_CODEC_ID_PCM_S8, 0x00 }, + { AV_CODEC_ID_PCM_U8, 0x01 }, + { AV_CODEC_ID_PCM_S16LE, 0x02 }, + { AV_CODEC_ID_PCM_S16BE, 0x03 }, + { AV_CODEC_ID_PCM_S24LE, 0x04 }, + { AV_CODEC_ID_PCM_S24BE, 0x05 }, + { AV_CODEC_ID_PCM_S32LE, 0x06 }, + { AV_CODEC_ID_PCM_S32BE, 0x07 }, + { AV_CODEC_ID_PCM_F32LE, 0x20 }, + { AV_CODEC_ID_PCM_F32BE, 0x21 }, + { AV_CODEC_ID_PCM_F64LE, 0x22 }, + { AV_CODEC_ID_PCM_F64BE, 0x23 }, +}; + +static inline uint32_t ogg_get_pcm_format_id(uint32_t codec_id) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(ogg_pcm_codecs); i++) + if (ogg_pcm_codecs[i].codec_id == codec_id) + return ogg_pcm_codecs[i].format_id; + + return 0; +} + static void ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) { OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data; @@ -363,6 +393,39 @@ static int ogg_build_speex_headers(AVCodecParameters *par, return 0; } +#define OGGPCM_HEADER_SIZE 224 + +static int ogg_build_pcm_headers(AVCodecParameters *par, + OGGStreamContext *oggstream, int bitexact, + AVDictionary **m) +{ + uint8_t *p; + + // first packet: OggPCM header + p = av_mallocz(OGGPCM_HEADER_SIZE); + if (!p) + return AVERROR(ENOMEM); + oggstream->header[0] = p; + oggstream->header_len[0] = OGGPCM_HEADER_SIZE; + bytestream_put_buffer(&p, "PCM ", 8); // Identifier + bytestream_put_be16(&p, 0x00); // VMAJ + bytestream_put_be16(&p, 0x00); // VMIN + bytestream_put_be32(&p, ogg_get_pcm_format_id(par->codec_id)); // PCM fmt + bytestream_put_be32(&p, par->sample_rate); // Sample rate + bytestream_put_byte(&p, 0); // Significant bits (0 == Same as fmt) + bytestream_put_byte(&p, par->channels); // Channels + bytestream_put_be16(&p, 0); // Max frames per packet TODO:// Actually calculate max frames per packet + bytestream_put_be32(&p, 0); // Number of extra headers + + // second packet: VorbisComment + p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0, NULL, 0); + if (!p) + return AVERROR(ENOMEM); + oggstream->header[1] = p; + + return 0; +} + #define OPUS_HEADER_SIZE 19 static int ogg_build_opus_headers(AVCodecParameters *par, @@ -487,18 +550,20 @@ static int ogg_init(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); } - if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS && - st->codecpar->codec_id != AV_CODEC_ID_THEORA && - st->codecpar->codec_id != AV_CODEC_ID_SPEEX && - st->codecpar->codec_id != AV_CODEC_ID_FLAC && - st->codecpar->codec_id != AV_CODEC_ID_OPUS && + if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS && + st->codecpar->codec_id != AV_CODEC_ID_THEORA && + st->codecpar->codec_id != AV_CODEC_ID_SPEEX && + st->codecpar->codec_id != AV_CODEC_ID_FLAC && + st->codecpar->codec_id != AV_CODEC_ID_OPUS && + !ogg_get_pcm_format_id(st->codecpar->codec_id) && st->codecpar->codec_id != AV_CODEC_ID_VP8) { av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i); return AVERROR(EINVAL); } if ((!st->codecpar->extradata || !st->codecpar->extradata_size) && - st->codecpar->codec_id != AV_CODEC_ID_VP8) { + st->codecpar->codec_id != AV_CODEC_ID_VP8 && + !ogg_get_pcm_format_id(st->codecpar->codec_id)) { av_log(s, AV_LOG_ERROR, "No extradata present\n"); return AVERROR_INVALIDDATA; } @@ -553,6 +618,14 @@ static int ogg_init(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Error writing VP8 headers\n"); return err; } + } else if (ogg_get_pcm_format_id(st->codecpar->codec_id)) { + int err = ogg_build_pcm_headers(st->codecpar, oggstream, + s->flags & AVFMT_FLAG_BITEXACT, + &st->metadata); + if (err) { + av_log(s, AV_LOG_ERROR, "Error writing OggPCM headers\n"); + return err; + } } else { uint8_t *p; const char *cstr = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? "vorbis" : "theora"; @@ -729,6 +802,7 @@ static void ogg_free(AVFormatContext *s) if (st->codecpar->codec_id == AV_CODEC_ID_FLAC || st->codecpar->codec_id == AV_CODEC_ID_SPEEX || st->codecpar->codec_id == AV_CODEC_ID_OPUS || + ogg_get_pcm_format_id(st->codecpar->codec_id) || st->codecpar->codec_id == AV_CODEC_ID_VP8) { av_freep(&oggstream->header[0]); }