Parse files consisting of multiple concatenated sequences.
[dirac_parser.git] / src / decoder / Schrodec.cpp
blob95c0f473c4516be5f5dec6c489204c8dcad4876d
1 /* ***** BEGIN LICENSE BLOCK *****
3 * $Id: $
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
19 * Corporation.
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
35 * or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
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;
50 namespace
52 IDecoder::size_type
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;
59 return ret;
61 } /* */
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 )
68 initSchro();
69 fetchSequenceHeader();
72 Schrodec::~Schrodec() {}
74 Schrodec::VideoFormatSharedPtr
75 Schrodec::getVideoFormat() const
77 return videoFormat_;
80 void
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 );
91 void
92 Schrodec::initSchro()
94 schro_init();
95 createDecoder();
98 void
99 Schrodec::resetDecoder()
101 if ( decoder_.get() ) {
102 decoder_.reset();
103 createDecoder();
104 numberOfDecodedFrames_ = 0;
105 fetchSequenceHeader();
109 void
110 Schrodec::deleteBuffer ( SchroBuffer* schrobuffer, void* inputBuffer )
112 delete static_cast<dirac::decoder::IDecoder::InputBuffer*> ( inputBuffer );
115 void
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;
127 void
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() );
133 AccessUnit au;
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() )
147 , free );
148 videoFormat_.swap ( tmp );
149 if ( !videoFormat_.get() ) {
150 throw DecoderException ( "failed to extract video format" );
154 void
155 Schrodec::signOff()
157 DIRAC_MESSAGE_ASSERT ( "decoder cannot be null", 0 != decoder_.get() );
159 schro_decoder_push_end_of_stream ( decoder_.get() );
162 IDecoderState*
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
171 void
172 Schrodec::pushBits()
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
178 AccessUnit au;
179 do {
180 if ( !parser_->getNextAccessUnit ( au ) || au.isLastEndOfSequence()
181 || !parser_->moveCursorFwd() ) {
182 signOff();
183 return;
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
197 void
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
208 void
209 Schrodec::setFrame()
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()
215 , frameHeight()
216 , chromaFormat() ) );
217 SchroFrame* frame = schro_frame_new_from_data_I420 ( buffer
218 , frameWidth()
219 , frameHeight() );
220 schro_frame_set_free_callback ( frame, deleteFrame, this );
221 schro_decoder_add_output_picture ( decoder_.get(), frame );
224 void
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() );
231 if ( frame ) {
232 ++numberOfDecodedFrames_;
233 write ( frame );
234 schro_frame_unref ( frame );
238 bool
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 ) );
250 void
251 Schrodec::runDecoder()
253 DIRAC_MESSAGE_ASSERT ( "decoder cannot be null", 0 != decoder_.get() );
255 std::auto_ptr<IDecoderState> decoderState;
256 do {
257 std::auto_ptr<IDecoderState> tmp ( getState() );
258 decoderState = tmp; // the previous DecoderState gets deleted here
259 decoderState->doNextAction();
260 } while ( !decoderState->isEndOfSequence() );
263 IDecoder::size_type
264 Schrodec::numberOfFrames() const
266 return numberOfDecodedFrames_;
269 Schrodec::size_type
270 Schrodec::getFrameWidth() const
272 if ( videoFormat_.get() ) {
273 return videoFormat_->width;
275 else {
276 return 0;
280 IDecoder::size_type
281 Schrodec::getFrameHeight() const
283 if ( videoFormat_.get() ) {
284 return videoFormat_->height;
286 else {
287 return 0;
291 ChromaFormat
292 Schrodec::getChromaFormat() const
294 if ( videoFormat_.get() ) {
295 switch ( videoFormat_->chroma_format ) {
296 case ( SCHRO_CHROMA_444 ) :
297 return CHROMA_444;
298 // break;
299 case ( SCHRO_CHROMA_422 ) :
300 return CHROMA_422;
301 // break;
302 case ( SCHRO_CHROMA_420 ) :
303 return CHROMA_420;
304 // break;
305 default :
306 return UNDEFINED;
307 // break;
310 else {
311 return UNDEFINED;