1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2019 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 // activate some C99 macros like UINT64_C in "stdint.h" which used by FFmpeg
16 #ifndef __STDC_CONSTANT_MACROS
17 #define __STDC_CONSTANT_MACROS
20 #include <Media_CodecContext.hxx>
22 #include <Media_Frame.hxx>
23 #include <Media_FormatContext.hxx>
25 #include <Message.hxx>
26 #include <Message_Messenger.hxx>
27 #include <OSD_Parallel.hxx>
30 #include <Standard_WarningsDisable.hxx>
33 #include <libavformat/avformat.h>
35 #include <Standard_WarningsRestore.hxx>
38 IMPLEMENT_STANDARD_RTTIEXT(Media_CodecContext, Standard_Transient)
40 // =======================================================================
41 // function : Media_CodecContext
43 // =======================================================================
44 Media_CodecContext::Media_CodecContext()
48 myPtsStartStream(0.0),
51 myPixelAspectRatio (1.0f)
54 myCodecCtx = avcodec_alloc_context3 (NULL);
58 // =======================================================================
59 // function : ~Media_CodecContext
61 // =======================================================================
62 Media_CodecContext::~Media_CodecContext()
67 // =======================================================================
70 // =======================================================================
71 bool Media_CodecContext::Init (const AVStream& theStream,
72 double thePtsStartBase,
76 return Init (theStream, thePtsStartBase, theNbThreads, AV_CODEC_ID_NONE);
78 return Init (theStream, thePtsStartBase, theNbThreads, 0);
82 // =======================================================================
85 // =======================================================================
86 bool Media_CodecContext::Init (const AVStream& theStream,
87 double thePtsStartBase,
92 myStreamIndex = theStream.index;
93 if (avcodec_parameters_to_context (myCodecCtx, theStream.codecpar) < 0)
95 Message::DefaultMessenger()->Send ("Internal error: unable to copy codec parameters", Message_Fail);
100 myTimeBase = av_q2d (theStream.time_base);
101 myPtsStartBase = thePtsStartBase;
102 myPtsStartStream = Media_FormatContext::StreamUnitsToSeconds (theStream, theStream.start_time);
104 const AVCodecID aCodecId = theCodecId != AV_CODEC_ID_NONE ? (AVCodecID )theCodecId : theStream.codecpar->codec_id;
105 myCodec = avcodec_find_decoder (aCodecId);
108 Message::DefaultMessenger()->Send ("FFmpeg: unable to find decoder", Message_Fail);
113 myCodecCtx->codec_id = aCodecId;
114 AVDictionary* anOpts = NULL;
115 av_dict_set (&anOpts, "refcounted_frames", "1", 0);
116 if (theStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
118 myCodecCtx->thread_count = theNbThreads <= -1 ? OSD_Parallel::NbLogicalProcessors() : theNbThreads;
121 if (avcodec_open2 (myCodecCtx, myCodec, &anOpts) < 0)
123 Message::DefaultMessenger()->Send ("FFmpeg: unable to open decoder", Message_Fail);
128 myPixelAspectRatio = 1.0f;
129 if (theStream.sample_aspect_ratio.num && av_cmp_q(theStream.sample_aspect_ratio, myCodecCtx->sample_aspect_ratio))
131 myPixelAspectRatio = float(theStream.sample_aspect_ratio.num) / float(theStream.sample_aspect_ratio.den);
135 if (myCodecCtx->sample_aspect_ratio.num == 0
136 || myCodecCtx->sample_aspect_ratio.den == 0)
138 myPixelAspectRatio = 1.0f;
142 myPixelAspectRatio = float(myCodecCtx->sample_aspect_ratio.num) / float(myCodecCtx->sample_aspect_ratio.den);
146 if (theStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO
147 && (myCodecCtx->width <= 0
148 || myCodecCtx->height <= 0))
150 Message::DefaultMessenger()->Send ("FFmpeg: video stream has invalid dimensions", Message_Fail);
158 (void )thePtsStartBase;
165 // =======================================================================
168 // =======================================================================
169 void Media_CodecContext::Close()
171 if (myCodecCtx != NULL)
174 avcodec_free_context (&myCodecCtx);
179 // =======================================================================
182 // =======================================================================
183 void Media_CodecContext::Flush()
185 if (myCodecCtx != NULL)
188 avcodec_flush_buffers (myCodecCtx);
193 // =======================================================================
196 // =======================================================================
197 int Media_CodecContext::SizeX() const
200 return (myCodecCtx != NULL) ? myCodecCtx->width : 0;
206 // =======================================================================
209 // =======================================================================
210 int Media_CodecContext::SizeY() const
213 return (myCodecCtx != NULL) ? myCodecCtx->height : 0;
219 // =======================================================================
220 // function : CanProcessPacket
222 // =======================================================================
223 bool Media_CodecContext::CanProcessPacket (const Handle(Media_Packet)& thePacket) const
225 return !thePacket.IsNull()
226 && myStreamIndex == thePacket->StreamIndex();
229 // =======================================================================
230 // function : SendPacket
232 // =======================================================================
233 bool Media_CodecContext::SendPacket (const Handle(Media_Packet)& thePacket)
235 if (!CanProcessPacket (thePacket))
241 const int aRes = avcodec_send_packet (myCodecCtx, thePacket->Packet());
242 if (aRes < 0 && aRes != AVERROR_EOF)
252 // =======================================================================
253 // function : ReceiveFrame
255 // =======================================================================
256 bool Media_CodecContext::ReceiveFrame (const Handle(Media_Frame)& theFrame)
258 if (theFrame.IsNull())
264 const int aRes2 = avcodec_receive_frame (myCodecCtx, theFrame->ChangeFrame());
270 const int64_t aPacketPts = theFrame->BestEffortTimestamp() != AV_NOPTS_VALUE ? theFrame->BestEffortTimestamp() : 0;
271 const double aFramePts = double(aPacketPts) * myTimeBase - myPtsStartBase;
272 theFrame->SetPts (aFramePts);