1 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License
8 * Version 1.1 (the "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14 * the specific language governing rights and limitations under the License.
16 * The Original Code is BBC Research code.
18 * The Initial Developer of the Original Code is the British Broadcasting
20 * Portions created by the Initial Developer are Copyright (C) 2007.
21 * All Rights Reserved.
23 * Contributor(s): Andrea Gabriellini (Original Author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
27 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
28 * the GPL or the LGPL are applicable instead of those above. If you wish to
29 * allow use of your version of this file only under the terms of the either
30 * the GPL or LGPL and not to allow others to use your version of this file
31 * under the MPL, indicate your decision by deleting the provisions above
32 * and replace them with the notice and other provisions required by the GPL
33 * or LGPL. If you do not delete the provisions above, a recipient may use
34 * your version of this file under the terms of any one of the MPL, the GPL
36 * ***** END LICENSE BLOCK ***** */
42 #include <decoder/Schrodec.hpp>
44 #include <parser/AccessUnit.hpp>
45 #include <decoder/SchroState.hpp>
47 using namespace ::dirac::decoder;
48 using namespace ::dirac::parser_project;
53 getBufferSizeFroFrame ( SchroFrame* frame )
55 DIRAC_MESSAGE_ASSERT ( "frame cannot be null", 0 != frame );
57 IDecoder::size_type ret = 0;
58 for (int i=0; i<3; ++i) ret += frame->components[i].length;
63 //! init schro, parse and decode sequence header and obtain video format params
64 Schrodec::Schrodec ( IDecoder::ParserAutoPtr parser
65 , IDecoder::FrameManagerAutoPtr manager )
66 : IDecoder ( parser, manager ), numberOfDecodedFrames_ ( 0 )
69 fetchSequenceHeader();
72 Schrodec::~Schrodec() {}
74 Schrodec::VideoFormatSharedPtr
75 Schrodec::getVideoFormat() const
81 Schrodec::createDecoder()
83 DecoderSharedPtr tmp ( schro_decoder_new(), schro_decoder_free );
84 decoder_.swap ( tmp );
85 if ( !decoder_.get() ) {
86 throw DecoderException ( "failed to create schro decoder" );
88 schro_decoder_set_skip_ratio ( decoder_.get(), 1.0 );
99 Schrodec::resetDecoder()
101 if ( decoder_.get() ) {
104 numberOfDecodedFrames_ = 0;
105 fetchSequenceHeader();
110 Schrodec::deleteBuffer ( SchroBuffer* schrobuffer, void* inputBuffer )
112 delete static_cast<dirac::decoder::IDecoder::InputBuffer*> ( inputBuffer );
116 Schrodec::createSchroBuffer(IDecoder::AU& au, SchroBuffer*& schrobuffer )
118 InputBuffer* buf = au.releaseBuffer();
119 schrobuffer = schro_buffer_new_with_data ( &(*buf)[0] , buf->size() );
120 if ( !schrobuffer ) {
121 throw DecoderException ( "failed to create input buffer for schodec" );
123 schrobuffer->priv = buf;
124 schrobuffer->free = deleteBuffer;
128 Schrodec::fetchSequenceHeader()
130 DIRAC_MESSAGE_ASSERT ( "parser cannot be null", 0 != parser_.get() );
131 DIRAC_MESSAGE_ASSERT ( "decoder cannot be null", 0 != decoder_.get() );
134 if ( !parser_->getNextSequenceHeader ( au ) || au.empty() ) {
135 throw DecoderException ( "failed to parser sequence header" );
138 SchroBuffer* schrobuffer = 0;
139 createSchroBuffer ( au, schrobuffer );
141 if ( SCHRO_DECODER_FIRST_ACCESS_UNIT !=
142 schro_decoder_push ( decoder_.get(), schrobuffer ) ) {
143 throw DecoderException ( "failed to decode sequence header" );
146 VideoFormatSharedPtr tmp ( schro_decoder_get_video_format ( decoder_.get() )
148 videoFormat_.swap ( tmp );
149 if ( !videoFormat_.get() ) {
150 throw DecoderException ( "failed to extract video format" );
157 DIRAC_MESSAGE_ASSERT ( "decoder cannot be null", 0 != decoder_.get() );
159 schro_decoder_push_end_of_stream ( decoder_.get() );
163 Schrodec::getDecoderState()
165 DIRAC_MESSAGE_ASSERT ( "decoder cannot be null", 0 != decoder_.get() );
167 return makeSchroState ( *this, schro_decoder_wait ( decoder_.get() ) );
170 //! parse a picture and push it in the decoder
174 DIRAC_MESSAGE_ASSERT ( "parser and decoder cannot be null"
175 , 0 != parser_.get() && 0 != decoder_.get() );
177 // parse a picture, but check whether we reach the end of the sequence
180 if ( !parser_->getNextAccessUnit ( au ) || au.isLastEndOfSequence()
181 || !parser_->moveCursorFwd() ) {
185 } while ( !au.isPicture() );
187 SchroBuffer* schrobuffer = 0;
188 createSchroBuffer ( au, schrobuffer );
190 int it = schro_decoder_push ( decoder_.get(), schrobuffer );
191 if ( SCHRO_DECODER_ERROR == it ) {
192 throw DecoderException ( "failed to decode picture" );
196 //! static method used as a deleter for schro frame
198 Schrodec::deleteFrame ( SchroFrame* frame, void* decoder )
200 DIRAC_MESSAGE_ASSERT ( "frame cannot be null", 0 != frame );
201 DIRAC_MESSAGE_ASSERT ( "decoder cannot be null", 0 != decoder );
203 static_cast<Schrodec*> ( decoder )->manager_->release
204 ( static_cast<pointer> ( frame->components[0].data ) );
207 //! allocate memory for a frame worth of data
211 DIRAC_MESSAGE_ASSERT ( "parser, decoder and video format cannot be null"
212 , 0 != parser_.get() && 0 != decoder_.get()
213 && 0 != videoFormat_.get() );
214 pointer buffer = manager_->allocate ( getFrameBufferSize( frameWidth()
216 , chromaFormat() ) );
217 SchroFrame* frame = schro_frame_new_from_data_I420 ( buffer
220 schro_frame_set_free_callback ( frame, deleteFrame, this );
221 schro_decoder_add_output_picture ( decoder_.get(), frame );
225 Schrodec::pullFrameAndWrite()
227 DIRAC_MESSAGE_ASSERT ( "decoder and manager cannot be null"
228 , 0 != decoder_.get() && 0 != manager_.get() );
230 SchroFrame* frame = schro_decoder_pull ( decoder_.get() );
232 ++numberOfDecodedFrames_;
234 schro_frame_unref ( frame );
239 Schrodec::write ( SchroFrame* frame )
241 DIRAC_MESSAGE_ASSERT ( "frame cannot be null", 0 != frame );
242 DIRAC_MESSAGE_ASSERT ( "videoformat cannot be null", 0 != videoFormat_.get() );
243 DIRAC_MESSAGE_ASSERT ( "frame manager cannot be null", 0 != manager_.get() );
245 // here we can format the data for output, if required
246 return manager_->write ( static_cast<pointer> ( frame->components[0].data )
247 , getBufferSizeFroFrame ( frame ) );
251 Schrodec::runDecoder()
253 DIRAC_MESSAGE_ASSERT ( "decoder cannot be null", 0 != decoder_.get() );
255 std::auto_ptr<IDecoderState> decoderState;
257 std::auto_ptr<IDecoderState> tmp ( getState() );
258 decoderState = tmp; // the previous DecoderState gets deleted here
259 decoderState->doNextAction();
260 } while ( !decoderState->isEndOfSequence() );
264 Schrodec::numberOfFrames() const
266 return numberOfDecodedFrames_;
270 Schrodec::getFrameWidth() const
272 if ( videoFormat_.get() ) {
273 return videoFormat_->width;
281 Schrodec::getFrameHeight() const
283 if ( videoFormat_.get() ) {
284 return videoFormat_->height;
292 Schrodec::getChromaFormat() const
294 if ( videoFormat_.get() ) {
295 switch ( videoFormat_->chroma_format ) {
296 case ( SCHRO_CHROMA_444 ) :
299 case ( SCHRO_CHROMA_422 ) :
302 case ( SCHRO_CHROMA_420 ) :