mirror of
				https://github.com/nyanmisaka/ffmpeg-rockchip.git
				synced 2025-10-31 04:26:37 +08:00 
			
		
		
		
	 c112be25f7
			
		
	
	c112be25f7
	
	
	
		
			
			Also use a unsigned constant for the shift calculation, as 1 << 31 is undefined for int32_t. This is also fixed oggparsetheora. This fixes ubsan runtime error: shift exponent is too large for 32-bit type 'int' Reviewed-by: Michael Niedermayer <michael@niedermayer.cc> Signed-off-by: Andreas Cadhalpun <Andreas.Cadhalpun@googlemail.com>
		
			
				
	
	
		
			215 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  *    Copyright (C) 2005  Matthieu CASTET, Alex Beregszaszi
 | |
|  *
 | |
|  *    Permission is hereby granted, free of charge, to any person
 | |
|  *    obtaining a copy of this software and associated documentation
 | |
|  *    files (the "Software"), to deal in the Software without
 | |
|  *    restriction, including without limitation the rights to use, copy,
 | |
|  *    modify, merge, publish, distribute, sublicense, and/or sell copies
 | |
|  *    of the Software, and to permit persons to whom the Software is
 | |
|  *    furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  *    The above copyright notice and this permission notice shall be
 | |
|  *    included in all copies or substantial portions of the Software.
 | |
|  *
 | |
|  *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
|  *    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
|  *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
|  *    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 | |
|  *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | |
|  *    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
|  *    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
|  *    DEALINGS IN THE SOFTWARE.
 | |
|  **/
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include "libavutil/bswap.h"
 | |
| #include "libavcodec/get_bits.h"
 | |
| #include "avformat.h"
 | |
| #include "internal.h"
 | |
| #include "oggdec.h"
 | |
| 
 | |
| typedef struct TheoraParams {
 | |
|     int gpshift;
 | |
|     int gpmask;
 | |
|     unsigned version;
 | |
| } TheoraParams;
 | |
| 
 | |
| static int theora_header(AVFormatContext *s, int idx)
 | |
| {
 | |
|     struct ogg *ogg       = s->priv_data;
 | |
|     struct ogg_stream *os = ogg->streams + idx;
 | |
|     AVStream *st          = s->streams[idx];
 | |
|     TheoraParams *thp     = os->private;
 | |
|     int cds               = st->codec->extradata_size + os->psize + 2;
 | |
|     int err;
 | |
|     uint8_t *cdp;
 | |
| 
 | |
|     if (!(os->buf[os->pstart] & 0x80))
 | |
|         return 0;
 | |
| 
 | |
|     if (!thp) {
 | |
|         thp = av_mallocz(sizeof(*thp));
 | |
|         if (!thp)
 | |
|             return AVERROR(ENOMEM);
 | |
|         os->private = thp;
 | |
|     }
 | |
| 
 | |
|     switch (os->buf[os->pstart]) {
 | |
|     case 0x80: {
 | |
|         GetBitContext gb;
 | |
|         AVRational timebase;
 | |
| 
 | |
|         init_get_bits(&gb, os->buf + os->pstart, os->psize * 8);
 | |
| 
 | |
|         /* 0x80"theora" */
 | |
|         skip_bits_long(&gb, 7 * 8);
 | |
| 
 | |
|         thp->version = get_bits_long(&gb, 24);
 | |
|         if (thp->version < 0x030100) {
 | |
|             av_log(s, AV_LOG_ERROR,
 | |
|                    "Too old or unsupported Theora (%x)\n", thp->version);
 | |
|             return AVERROR(ENOSYS);
 | |
|         }
 | |
| 
 | |
|         st->codec->width  = get_bits(&gb, 16) << 4;
 | |
|         st->codec->height = get_bits(&gb, 16) << 4;
 | |
| 
 | |
|         if (thp->version >= 0x030400)
 | |
|             skip_bits(&gb, 100);
 | |
| 
 | |
|         if (thp->version >= 0x030200) {
 | |
|             int width  = get_bits_long(&gb, 24);
 | |
|             int height = get_bits_long(&gb, 24);
 | |
|             if (width  <= st->codec->width  && width  > st->codec->width  - 16 &&
 | |
|                 height <= st->codec->height && height > st->codec->height - 16) {
 | |
|                 st->codec->width  = width;
 | |
|                 st->codec->height = height;
 | |
|             }
 | |
| 
 | |
|             skip_bits(&gb, 16);
 | |
|         }
 | |
| 
 | |
|         timebase.den = get_bits_long(&gb, 32);
 | |
|         timebase.num = get_bits_long(&gb, 32);
 | |
|         if (!(timebase.num > 0 && timebase.den > 0)) {
 | |
|             av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
 | |
|             timebase.num = 1;
 | |
|             timebase.den = 25;
 | |
|         }
 | |
|         avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
 | |
| 
 | |
|         st->sample_aspect_ratio.num = get_bits_long(&gb, 24);
 | |
|         st->sample_aspect_ratio.den = get_bits_long(&gb, 24);
 | |
| 
 | |
|         if (thp->version >= 0x030200)
 | |
|             skip_bits_long(&gb, 38);
 | |
|         if (thp->version >= 0x304000)
 | |
|             skip_bits(&gb, 2);
 | |
| 
 | |
|         thp->gpshift = get_bits(&gb, 5);
 | |
|         thp->gpmask  = (1U << thp->gpshift) - 1;
 | |
| 
 | |
|         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
 | |
|         st->codec->codec_id   = AV_CODEC_ID_THEORA;
 | |
|         st->need_parsing      = AVSTREAM_PARSE_HEADERS;
 | |
|     }
 | |
|     break;
 | |
|     case 0x81:
 | |
|         ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7);
 | |
|     case 0x82:
 | |
|         if (!thp->version)
 | |
|             return AVERROR_INVALIDDATA;
 | |
|         break;
 | |
|     default:
 | |
|         av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
 | |
|         return AVERROR_INVALIDDATA;
 | |
|     }
 | |
| 
 | |
|     if ((err = av_reallocp(&st->codec->extradata,
 | |
|                            cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
 | |
|         st->codec->extradata_size = 0;
 | |
|         return err;
 | |
|     }
 | |
|     memset(st->codec->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE);
 | |
| 
 | |
|     cdp    = st->codec->extradata + st->codec->extradata_size;
 | |
|     *cdp++ = os->psize >> 8;
 | |
|     *cdp++ = os->psize & 0xff;
 | |
|     memcpy(cdp, os->buf + os->pstart, os->psize);
 | |
|     st->codec->extradata_size = cds;
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
 | |
|                                int64_t *dts)
 | |
| {
 | |
|     struct ogg *ogg       = ctx->priv_data;
 | |
|     struct ogg_stream *os = ogg->streams + idx;
 | |
|     TheoraParams *thp     = os->private;
 | |
|     uint64_t iframe, pframe;
 | |
| 
 | |
|     if (!thp)
 | |
|         return AV_NOPTS_VALUE;
 | |
| 
 | |
|     iframe = gp >> thp->gpshift;
 | |
|     pframe = gp & thp->gpmask;
 | |
| 
 | |
|     if (thp->version < 0x030201)
 | |
|         iframe++;
 | |
| 
 | |
|     if (!pframe)
 | |
|         os->pflags |= AV_PKT_FLAG_KEY;
 | |
| 
 | |
|     if (dts)
 | |
|         *dts = iframe + pframe;
 | |
| 
 | |
|     return iframe + pframe;
 | |
| }
 | |
| 
 | |
| static int theora_packet(AVFormatContext *s, int idx)
 | |
| {
 | |
|     struct ogg *ogg = s->priv_data;
 | |
|     struct ogg_stream *os = ogg->streams + idx;
 | |
|     int duration;
 | |
| 
 | |
|     /* first packet handling
 | |
|        here we parse the duration of each packet in the first page and compare
 | |
|        the total duration to the page granule to find the encoder delay and
 | |
|        set the first timestamp */
 | |
| 
 | |
|     if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
 | |
|         int seg;
 | |
| 
 | |
|         duration = 1;
 | |
|         for (seg = os->segp; seg < os->nsegs; seg++) {
 | |
|             if (os->segments[seg] < 255)
 | |
|                 duration ++;
 | |
|         }
 | |
| 
 | |
|         os->lastpts = os->lastdts   = theora_gptopts(s, idx, os->granule, NULL) - duration;
 | |
|         if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
 | |
|             s->streams[idx]->start_time = os->lastpts;
 | |
|             if (s->streams[idx]->duration > 0)
 | |
|                 s->streams[idx]->duration -= s->streams[idx]->start_time;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* parse packet duration */
 | |
|     if (os->psize > 0) {
 | |
|         os->pduration = 1;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| const struct ogg_codec ff_theora_codec = {
 | |
|     .magic     = "\200theora",
 | |
|     .magicsize = 7,
 | |
|     .header    = theora_header,
 | |
|     .packet    = theora_packet,
 | |
|     .gptopts   = theora_gptopts,
 | |
|     .nb_header = 3,
 | |
| };
 |