mirror of
				https://git.ffmpeg.org/ffmpeg.git
				synced 2025-10-31 07:40:55 +00:00 
			
		
		
		
	Port SMPTE S302M audio decoder from FFmbc 0.3.
This commit is contained in:
		
							parent
							
								
									b44c8ad280
								
							
						
					
					
						commit
						9aa91043f3
					
				
					 7 changed files with 147 additions and 0 deletions
				
			
		|  | @ -7,6 +7,7 @@ version <next>: | |||
| - Lots of deprecated API cruft removed | ||||
| - fft and imdct optimizations for AVX (Sandy Bridge) processors | ||||
| - DPX image encoder | ||||
| - SMPTE 302M AES3 audio decoder | ||||
| 
 | ||||
| 
 | ||||
| version 0.7_beta1: | ||||
|  |  | |||
|  | @ -673,6 +673,7 @@ following image formats are supported: | |||
| @item Sierra VMD audio       @tab     @tab  X | ||||
|     @tab Used in Sierra VMD files. | ||||
| @item Smacker audio          @tab     @tab  X | ||||
| @item SMPTE 302M AES3 audio  @tab     @tab  X | ||||
| @item Speex                  @tab     @tab  E | ||||
|     @tab supported through external library libspeex | ||||
| @item True Audio (TTA)       @tab     @tab  X | ||||
|  |  | |||
|  | @ -324,6 +324,7 @@ OBJS-$(CONFIG_RV30_DECODER)            += rv30.o rv34.o rv30dsp.o        \ | |||
|                                           mpegvideo.o error_resilience.o | ||||
| OBJS-$(CONFIG_RV40_DECODER)            += rv40.o rv34.o rv40dsp.o        \
 | ||||
|                                           mpegvideo.o error_resilience.o | ||||
| OBJS-$(CONFIG_S302M_DECODER)           += s302m.o | ||||
| OBJS-$(CONFIG_SGI_DECODER)             += sgidec.o | ||||
| OBJS-$(CONFIG_SGI_ENCODER)             += sgienc.o rle.o | ||||
| OBJS-$(CONFIG_SHORTEN_DECODER)         += shorten.o | ||||
|  |  | |||
|  | @ -177,6 +177,7 @@ void avcodec_register_all(void) | |||
|     REGISTER_ENCDEC  (RV20, rv20); | ||||
|     REGISTER_DECODER (RV30, rv30); | ||||
|     REGISTER_DECODER (RV40, rv40); | ||||
|     REGISTER_DECODER (S302M, s302m); | ||||
|     REGISTER_ENCDEC  (SGI, sgi); | ||||
|     REGISTER_DECODER (SMACKER, smacker); | ||||
|     REGISTER_DECODER (SMC, smc); | ||||
|  |  | |||
|  | @ -232,6 +232,7 @@ enum CodecID { | |||
|     CODEC_ID_PCM_F64LE, | ||||
|     CODEC_ID_PCM_BLURAY, | ||||
|     CODEC_ID_PCM_LXF, | ||||
|     CODEC_ID_S302M, | ||||
| 
 | ||||
|     /* various ADPCM codecs */ | ||||
|     CODEC_ID_ADPCM_IMA_QT= 0x11000, | ||||
|  |  | |||
							
								
								
									
										141
									
								
								libavcodec/s302m.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								libavcodec/s302m.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,141 @@ | |||
| /*
 | ||||
|  * SMPTE 302M decoder | ||||
|  * Copyright (c) 2008 Laurent Aimar <fenrir@videolan.org> | ||||
|  * Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com> | ||||
|  * | ||||
|  * This file is part of Libav. | ||||
|  * | ||||
|  * Libav is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * Libav is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with Libav; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
| 
 | ||||
| #include "libavutil/intreadwrite.h" | ||||
| #include "avcodec.h" | ||||
| 
 | ||||
| #define AES3_HEADER_LEN 4 | ||||
| 
 | ||||
| static int s302m_parse_frame_header(AVCodecContext *avctx, const uint8_t *buf, | ||||
|                                     int buf_size) | ||||
| { | ||||
|     uint32_t h; | ||||
|     int frame_size, channels, id, bits; | ||||
| 
 | ||||
|     if (buf_size <= AES3_HEADER_LEN) { | ||||
|         av_log(avctx, AV_LOG_ERROR, "frame is too short\n"); | ||||
|         return AVERROR_INVALIDDATA; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * AES3 header : | ||||
|      * size:            16 | ||||
|      * number channels   2 | ||||
|      * channel_id        8 | ||||
|      * bits per samples  2 | ||||
|      * alignments        4 | ||||
|      */ | ||||
| 
 | ||||
|     h = AV_RB32(buf); | ||||
|     frame_size =  (h >> 16) & 0xffff; | ||||
|     channels   = ((h >> 14) & 0x0003) * 2 +  2; | ||||
|     id         =  (h >>  6) & 0x00ff; | ||||
|     bits       = ((h >>  4) & 0x0003) * 4 + 16; | ||||
| 
 | ||||
|     if (AES3_HEADER_LEN + frame_size != buf_size || bits > 24) { | ||||
|         av_log(avctx, AV_LOG_ERROR, "frame has invalid header\n"); | ||||
|         return AVERROR_INVALIDDATA; | ||||
|     } | ||||
| 
 | ||||
|     /* Set output properties */ | ||||
|     avctx->bits_per_coded_sample = bits; | ||||
|     if (bits > 16) | ||||
|         avctx->sample_fmt = SAMPLE_FMT_S32; | ||||
|     else | ||||
|         avctx->sample_fmt = SAMPLE_FMT_S16; | ||||
| 
 | ||||
|     avctx->channels    = channels; | ||||
|     avctx->sample_rate = 48000; | ||||
|     avctx->bit_rate    = 48000 * avctx->channels * (avctx->bits_per_coded_sample + 4) + | ||||
|                          32 * (48000 / (buf_size * 8 / | ||||
|                                         (avctx->channels * | ||||
|                                          (avctx->bits_per_coded_sample + 4)))); | ||||
| 
 | ||||
|     return frame_size; | ||||
| } | ||||
| 
 | ||||
| static int s302m_decode_frame(AVCodecContext *avctx, void *data, | ||||
|                               int *data_size, AVPacket *avpkt) | ||||
| { | ||||
|     const uint8_t *buf = avpkt->data; | ||||
|     int buf_size       = avpkt->size; | ||||
| 
 | ||||
|     int frame_size = s302m_parse_frame_header(avctx, buf, buf_size); | ||||
|     if (frame_size < 0) | ||||
|         return frame_size; | ||||
| 
 | ||||
|     buf_size -= AES3_HEADER_LEN; | ||||
|     buf      += AES3_HEADER_LEN; | ||||
| 
 | ||||
|     if (*data_size < 4 * buf_size * 8 / (avctx->bits_per_coded_sample + 4)) | ||||
|         return -1; | ||||
| 
 | ||||
|     if (avctx->bits_per_coded_sample == 24) { | ||||
|         uint32_t *o = data; | ||||
|         for (; buf_size > 6; buf_size -= 7) { | ||||
|             *o++ = (av_reverse[buf[2]]        << 24) | | ||||
|                    (av_reverse[buf[1]]        << 16) | | ||||
|                    (av_reverse[buf[0]]        <<  8); | ||||
|             *o++ = (av_reverse[buf[6] & 0xf0] << 28) | | ||||
|                    (av_reverse[buf[5]]        << 20) | | ||||
|                    (av_reverse[buf[4]]        << 12) | | ||||
|                    (av_reverse[buf[3] & 0x0f] <<  8); | ||||
|             buf += 7; | ||||
|         } | ||||
|         *data_size = (uint8_t*) o - (uint8_t*) data; | ||||
|     } else if (avctx->bits_per_coded_sample == 20) { | ||||
|         uint32_t *o = data; | ||||
|         for (; buf_size > 5; buf_size -= 6) { | ||||
|             *o++ = (av_reverse[buf[2] & 0xf0] << 28) | | ||||
|                    (av_reverse[buf[1]]        << 20) | | ||||
|                    (av_reverse[buf[0]]        << 12); | ||||
|             *o++ = (av_reverse[buf[5] & 0xf0] << 28) | | ||||
|                    (av_reverse[buf[4]]        << 20) | | ||||
|                    (av_reverse[buf[3]]        << 12); | ||||
|             buf += 6; | ||||
|         } | ||||
|         *data_size = (uint8_t*) o - (uint8_t*) data; | ||||
|     } else { | ||||
|         uint16_t *o = data; | ||||
|         for (; buf_size > 4; buf_size -= 5) { | ||||
|             *o++ = (av_reverse[buf[1]]        <<  8) | | ||||
|                     av_reverse[buf[0]]; | ||||
|             *o++ = (av_reverse[buf[4] & 0xf0] << 12) | | ||||
|                    (av_reverse[buf[3]]        <<  4) | | ||||
|                     av_reverse[buf[2] & 0x0f]; | ||||
|             buf += 5; | ||||
|         } | ||||
|         *data_size = (uint8_t*) o - (uint8_t*) data; | ||||
|     } | ||||
| 
 | ||||
|     return buf - avpkt->data; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| AVCodec ff_s302m_decoder = { | ||||
|     .name           = "s302m", | ||||
|     .type           = AVMEDIA_TYPE_AUDIO, | ||||
|     .id             = CODEC_ID_S302M, | ||||
|     .priv_data_size = 0, | ||||
|     .decode         = s302m_decode_frame, | ||||
|     .long_name      = NULL_IF_CONFIG_SMALL("SMPTE 302M"), | ||||
| }; | ||||
|  | @ -524,6 +524,7 @@ static const StreamType MISC_types[] = { | |||
| static const StreamType REGD_types[] = { | ||||
|     { MKTAG('d','r','a','c'), AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC }, | ||||
|     { MKTAG('A','C','-','3'), AVMEDIA_TYPE_AUDIO,   CODEC_ID_AC3 }, | ||||
|     { MKTAG('B','S','S','D'), AVMEDIA_TYPE_AUDIO, CODEC_ID_S302M }, | ||||
|     { 0 }, | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Baptiste Coudurier
						Baptiste Coudurier