AVPKit
StreamCoder.cpp
1 /*******************************************************************************
2  * Copyright (c) 2024, 2026, Olivier Ayache. All rights reserved.
3  *
4  * This file is part of AVPKit.
5  *
6  * AVPKit is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * AVPKit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with AVPKit. If not, see <http://www.gnu.org/licenses/>.
18  *******************************************************************************/
19 
20 #include <stdexcept>
21 #include <cstring>
22 #include <string>
23 
24 #include <com/avpkit/ferry/Logger.h>
25 #include <com/avpkit/ferry/RefPointer.h>
26 
27 #include <com/avpkit/core/Global.h>
28 #include <com/avpkit/core/StreamCoder.h>
29 #include <com/avpkit/core/Codec.h>
30 #include <com/avpkit/core/Rational.h>
31 #include <com/avpkit/core/AudioSamples.h>
32 #include <com/avpkit/core/VideoPicture.h>
33 #include <com/avpkit/core/Packet.h>
34 #include <com/avpkit/core/Property.h>
35 #include <com/avpkit/core/MetaData.h>
36 #include <com/avpkit/ferry/JNIHelper.h>
37 
38 extern "C" {
39 #include <libavutil/dict.h>
40 #include <libavutil/channel_layout.h>
41 #include <libavutil/samplefmt.h>
42 #include <libavcodec/mediacodec.h>
43 #include <signal.h>
44 
45 #include "Error.h"
46 }
47 VS_LOG_SETUP(VS_CPP_PACKAGE);
48 
49 namespace com {
50 namespace avpkit {
51 namespace core {
52 using namespace com::avpkit::ferry;
53 
54 StreamCoder::StreamCoder() :
55  mCodec(0)
56 {
57  mCodecContext = 0;
58  swrContext = NULL;
59  // default to DECODING.
60  mDirection = DECODING;
61  mOpened = false;
62  mStream = 0;
63  mAudioFrameBuffer = 0;
64  mBytesInFrameBuffer = 0;
65  mPtsOfFrameBuffer = Global::NO_PTS;
66  mFakePtsTimeBase = IRational::make(1, AV_TIME_BASE);
67  mFakeNextPts = Global::NO_PTS;
68  mFakeCurrPts = Global::NO_PTS;
69  mLastPtsEncoded = Global::NO_PTS;
70  mSamplesCoded = 0;
71  mLastExternallySetTimeStamp = Global::NO_PTS;
72  mDefaultAudioFrameSize = 576;
73  mNumDroppedFrames = 0;
74  mAutomaticallyStampPacketsForStream = true;
75  for(uint32_t i = 0; i < sizeof(mPtsBuffer)/sizeof(mPtsBuffer[0]); i++)
76  {
77  mPtsBuffer[i] = Global::NO_PTS;
78  }
79 }
80 
81 StreamCoder::~StreamCoder()
82 {
83  reset();
84 }
85 
86 void
87 StreamCoder::resetOptions(AVCodecContext* ctx)
88 {
89  if (!ctx)
90  return;
91  if (ctx->codec && ctx->codec->priv_class && ctx->priv_data)
92  av_opt_free(ctx->priv_data);
93  av_opt_free(ctx);
94  av_freep(&ctx->priv_data);
95 }
96 
97 void
98 StreamCoder::reset()
99 {
100  // Auto-close if the caller forgot to close this
101  // stream-coder
102  if (mOpened)
103  {
104  VS_LOG_DEBUG("Closing dangling StreamCoder");
105  (void) this->close();
106  }
107 
108  mAutomaticallyStampPacketsForStream = true;
109  mOpened = false;
110  // Don't free if we're attached to a Stream.
111  // The Container will do that.
112  if (mCodecContext) {
113  // for reasons that I'm sure they will fix some day, avformat_free_context
114  // does not free private options. it should.
115  resetOptions(mCodecContext);
116  if(!mStream)
117  {
118  av_freep(&mCodecContext->extradata);
119  av_freep(&mCodecContext->subtitle_header);
120  avcodec_free_context(&mCodecContext);
121 
122 #ifdef __ANDROID__
123  mediacodec_free_context(mCodecContext);
124 #endif
125  av_freep(&mCodecContext);
126  }
127  }
128  //avcodec_free_context(&mCodecContext);
129  mCodecContext = 0;
130  // We do not refcount the stream
131  mStream = 0;
132 }
133 
134 int32_t
135 StreamCoder :: readyAVContexts(
136  Direction aDirection,
137  StreamCoder *aCoder,
138  Stream* aStream,
139  Codec *aCodec,
140  AVCodecContext *avContext,
141  const AVCodec *avCodec)
142 {
143  int retval = -1;
144  if (!avContext)
145  return retval;
146 
147  if (!aCodec) {
148  if (avCodec) {
149  aCoder->mCodec = Codec::make(avCodec);
150  } else if (aDirection == ENCODING) {
151  aCoder->mCodec = static_cast<Codec*>(ICodec::findEncodingCodecByIntID(avContext->codec_id));
152  } else {
153  aCoder->mCodec = static_cast<Codec*>(ICodec::findDecodingCodecByIntID(avContext->codec_id));
154  }
155  } else
156  aCoder->mCodec.reset(aCodec, true);
157 
158  aCodec = aCoder->mCodec.value(); // re-use reference
159  avCodec = aCodec ? aCodec->getAVCodec() : 0;
160  if (aCoder->mCodecContext) {
161  // was previously set; we should do something about that.
162 // VS_LOG_ERROR("Warning... mojo rising");
163  resetOptions(aCoder->mCodecContext);
164  }
165  aCoder->mCodecContext = avContext;
166  aCoder->setStream(aStream, true);
167  aCoder->mDirection = aDirection;
168 
169  avContext->opaque = aCodec;
170 
171  // these settings are necessary to have property setting work correctly
172  // and avContext->codec will need to be temporarily disabled BEFORE
173  // #open is called.
174  avContext->codec_id = avCodec ? avCodec->id : AV_CODEC_ID_NONE;
175  avContext->codec_type = avCodec ? avCodec->type : AVMEDIA_TYPE_UNKNOWN;
176  avContext->codec = avCodec;
177 
178  if (aDirection == DECODING && aStream)
179  avContext->pkt_timebase = aStream->getAVStream()->time_base;
180 
181  switch (avContext->codec_type)
182  {
183  case AVMEDIA_TYPE_AUDIO:
184  if (avContext->block_align == 1 && avContext->codec_id == AV_CODEC_ID_MP3)
185  avContext->block_align = 0;
186  if (avContext->codec_id == AV_CODEC_ID_AC3)
187  avContext->block_align = 0;
188  break;
189  default:
190  break;
191  }
192 
193  VS_LOG_TRACE("StreamCoder %p codec set to: %s [%s]",
194  aCoder,
195  avCodec ? avCodec->name : "unknown",
196  avCodec ? avCodec->long_name : "unknown; caller must call IStreamCoder.setCodec(ICodec)");
197  if (!avCodec && (avContext->codec_type == AVMEDIA_TYPE_AUDIO || avContext->codec_type == AVMEDIA_TYPE_VIDEO)) {
198  VS_LOG_WARN("DEPRECATED; StreamCoder %p created without Codec. Caller must call"
199  " IStreamCoder.setCodec(ICodec) before any other methods", aCoder);
200  }
201 
202  retval = 0;
203  return retval;
204 }
205 
206 void
207 StreamCoder::setCodec(ICodec * aCodec)
208 {
209  Codec* codec = static_cast<Codec*>(aCodec);
210  const AVCodec* avCodec = NULL;
211 
212  if (!codec) {
213  VS_LOG_INFO("Cannot set codec to null codec");
214  return;
215  }
216  avCodec = codec->getAVCodec();
217 
218  if (!mCodecContext) {
219  VS_LOG_ERROR("No codec context");
220  return;
221  }
222 
223  if (mCodecContext->codec_id != AV_CODEC_ID_NONE || mCodecContext->codec) {
224  VS_LOG_INFO("Codec already set to codec: %d. Ignoring setCodec call",
225  mCodecContext->codec_id);
226  return;
227  }
228 
229  if (mCodec.value() == aCodec) {
230  // setting to the same value; don't reset anything
231  return;
232  }
233 
234  if (mCodecContext) {
235  // avcodec_get_context_defaults3 does not clear these out if already allocated
236  // so we do.
237  resetOptions(mCodecContext);
238  av_freep(&mCodecContext->extradata);
239  av_freep(&mCodecContext->subtitle_header);
240  avcodec_free_context(&mCodecContext);
241  }
242 
243  mCodecContext = avcodec_alloc_context3(avCodec);
244 
245  if (mCodecContext)
246  readyAVContexts(mDirection,
247  this,
248  mStream,
249  codec,
250  mCodecContext,
251  NULL);
252 }
253 
254 void
255 StreamCoder::setCodec(ICodec::ID id)
256 {
257  setCodec((int32_t) id);
258 }
259 
260 void
261 StreamCoder::setCodec(int32_t id)
262 {
263  RefPointer<Codec> codec = 0;
264  if (ENCODING == mDirection)
265  {
266  codec = Codec::findEncodingCodecByIntID(id);
267  }
268  else
269  {
270  codec = Codec::findDecodingCodecByIntID(id);
271  }
272  if (codec)
273  setCodec(codec.value());
274 }
275 
276 StreamCoder*
277 StreamCoder::make(Direction direction, ICodec::ID id)
278 {
279  RefPointer<Codec> codec = 0;
280  StreamCoder* retval = NULL;
281  if (ENCODING == direction)
282  {
283  codec = Codec::findEncodingCodec(id);
284  }
285  else
286  {
287  codec = Codec::findDecodingCodec(id);
288  }
289  if (codec)
290  retval = StreamCoder::make(direction, codec.value());
291  return retval;
292 }
293 
294 StreamCoder *
295 StreamCoder :: make (Direction direction, Codec* codec)
296 {
297  StreamCoder* retval= NULL;
298 
299  try
300  {
301  AVCodecContext* codecCtx= NULL;
302  const AVCodec* avCodec = NULL;
303 
304  if (codec)
305  avCodec = codec->getAVCodec();
306 
307  retval = StreamCoder::make();
308  if (!retval)
309  throw std::bad_alloc();
310 
311  codecCtx = avcodec_alloc_context3(avCodec);
312 
313  if (readyAVContexts(
314  direction,
315  retval,
316  NULL,
317  codec,
318  codecCtx,
319  avCodec) < 0)
320  throw std::runtime_error("could not initialize codec");
321  }
322  catch (std::exception & e)
323  {
324  VS_REF_RELEASE(retval);
325  }
326  return retval;
327 }
328 
329 StreamCoder *
330 StreamCoder::make(Direction direction, IStreamCoder* aCoder)
331 {
332  StreamCoder *retval = NULL;
333  StreamCoder *coder = static_cast<StreamCoder*> (aCoder);
334 
335  try
336  {
337  if (!coder)
338  throw std::runtime_error("cannot make stream coder from null coder");
339 
340  RefPointer<Codec> codecToUse;
341 
342  codecToUse = coder->getCodec();
343 
344  retval = make(direction, codecToUse.value());
345  if (!retval)
346  throw std::bad_alloc();
347 
348  AVCodecContext* codec = retval->mCodecContext;
349  AVCodecContext* icodec = coder->mCodecContext;
350 
351  // no really; I hate FFmpeg memory management; a lot of sensible
352  // defaults got set up that we'll need to clear now.
353  resetOptions(codec);
354  av_freep(&codec->extradata);
355  av_freep(&codec->subtitle_header);
356 
357  // temporarily set this back to zero
358  codec->codec = NULL;
359  avcodec_copy_context(codec, icodec);
360  // and copy it back by hand to ensure setProperty methods
361  // work again
362  codec->codec = icodec->codec;
363 
364  RefPointer<IStream> stream = coder->getStream();
365  RefPointer<IRational> streamBase = stream ? stream->getTimeBase() : 0;
366  double base = streamBase ? streamBase->getDouble() : 0;
367 
368  if (base && av_q2d(icodec->time_base) * icodec->ticks_per_frame > base
369  && base < 1.0 / 1000)
370  {
371  codec->time_base.num *= icodec->ticks_per_frame;
372  }
373  if (!codec->time_base.num || !codec->time_base.den)
374  {
375  RefPointer<IRational> iStreamBase = coder->getTimeBase();
376  if (iStreamBase)
377  {
378  codec->time_base.num = iStreamBase->getNumerator();
379  codec->time_base.den = iStreamBase->getDenominator();
380  }
381  }
382 
383  if (readyAVContexts(
384  direction,
385  retval,
386  0,
387  codecToUse.value(),
388  codec,
389  icodec->codec) < 0)
390  throw std::runtime_error("could not initialize AVContext");
391 
392  }
393  catch (std::exception &e)
394  {
395  VS_LOG_WARN("Error: %s", e.what());
396  VS_REF_RELEASE(retval);
397  }
398  return retval;
399 }
400 
401 
402 StreamCoder *
403 StreamCoder::make(Direction direction,
404  AVCodecParameters *codecpar, const AVCodec* avCodec, Stream* stream)
405 {
406  StreamCoder* retval = NULL;
407  AVCodecContext* codecCtx = NULL;
408  try{
409  retval = StreamCoder::make();
410  if (!retval){
411  throw std::bad_alloc();
412  }
413  codecCtx = avcodec_alloc_context3(avCodec);
414  if (codecCtx && codecpar){
415  if (avcodec_parameters_to_context(codecCtx, codecpar) < 0)
416  throw std::runtime_error("could not initialize codec");
417  }
418 
419  if (readyAVContexts(
420  direction,
421  retval,
422  stream,
423  NULL,
424  codecCtx,
425  avCodec) < 0)
426  throw std::runtime_error("could not initialize AVContext");
427  }
428  catch (std::exception & e)
429  {
430  VS_REF_RELEASE(retval);
431  }
432  return retval;
433 }
434 
435 
436 StreamCoder *
437 StreamCoder::make(Direction direction, AVCodecContext * codecCtx,
438  const AVCodec* avCodec, Stream* stream)
439 {
440  StreamCoder *retval = NULL;
441  RefPointer<Codec> codec;
442 
443  if (codecCtx)
444  {
445  try
446  {
447  retval = StreamCoder::make();
448  if (readyAVContexts(
449  direction,
450  retval,
451  stream,
452  NULL,
453  codecCtx,
454  avCodec) < 0)
455  throw std::runtime_error("could not initialize codec");
456  }
457  catch (std::exception &e)
458  {
459  VS_REF_RELEASE(retval);
460  throw e;
461  }
462  }
463  return retval;
464 }
465 
466 IStream*
467 StreamCoder::getStream()
468 {
469  // Acquire for the caller.
470  VS_REF_ACQUIRE(mStream);
471  return mStream;
472 }
473 
474 Codec *
475 StreamCoder::getCodec()
476 {
477  return mCodec ? mCodec.get() : 0;
478 }
479 
481 StreamCoder::getCodecType()
482 {
483  ICodec::Type retval = ICodec::CODEC_TYPE_UNKNOWN;
484  if (mCodecContext)
485  {
486  retval = (ICodec::Type) mCodecContext->codec_type;
487  }
488  else
489  {
490  VS_LOG_WARN("Attempt to get CodecType from uninitialized StreamCoder");
491  }
492  return retval;
493 }
494 
496 StreamCoder::getCodecID()
497 {
498  ICodec::ID retval = ICodec::AV_CODEC_ID_NONE;
499  if (mCodecContext)
500  {
501  retval = (ICodec::ID) mCodecContext->codec_id;
502  }
503  else
504  {
505  VS_LOG_WARN("Attempt to get CodecID from uninitialized StreamCoder");
506  }
507  return retval;
508 }
509 
510 int32_t
511 StreamCoder::getBitRate()
512 {
513  return (mCodecContext ? mCodecContext->bit_rate : -1);
514 }
515 void
516 StreamCoder::setBitRate(int32_t val)
517 {
518  if (mCodecContext && !mOpened)
519  mCodecContext->bit_rate = val;
520 }
521 int32_t
522 StreamCoder::getBitRateTolerance()
523 {
524  return (mCodecContext ? mCodecContext->bit_rate_tolerance : -1);
525 }
526 void
527 StreamCoder::setBitRateTolerance(int32_t val)
528 {
529  if (mCodecContext && !mOpened)
530  mCodecContext->bit_rate_tolerance = val;
531 }
532 int32_t
533 StreamCoder::getHeight()
534 {
535  return (mCodecContext ? mCodecContext->height : -1);
536 }
537 
538 void
539 StreamCoder::setHeight(int32_t val)
540 {
541  if (mCodecContext && !mOpened)
542  mCodecContext->height = val;
543 }
544 
545 int32_t
546 StreamCoder::getWidth()
547 {
548  return (mCodecContext ? mCodecContext->width : -1);
549 }
550 
551 void
552 StreamCoder::setWidth(int32_t val)
553 {
554  if (mCodecContext && !mOpened)
555  mCodecContext->width = val;
556 }
557 
558 IRational*
559 StreamCoder::getTimeBase()
560 {
561  // we make a new value and return it; caller must
562  // release.
563  IRational *retval = 0;
564 
565  // annoyingly, some codec contexts will NOT have
566  // a timebase... so we take it from stream then.
567  if (mCodecContext && mCodecContext->time_base.den
568  && mCodecContext->time_base.num)
569  {
570  retval = Rational::make(&mCodecContext->time_base);
571  }
572  else if (mAutomaticallyStampPacketsForStream)
573  {
574  retval = mStream ? mStream->getTimeBase() : 0;
575  }
576 
577  return retval;
578 }
579 
580 void
581 StreamCoder::setTimeBase(IRational* src)
582 {
583  if (mCodecContext && src && !mOpened)
584  {
585  mCodecContext->time_base.num = src->getNumerator();
586  mCodecContext->time_base.den = src->getDenominator();
587  }
588  else
589  {
590  VS_LOG_INFO("Failed to setTimeBase on StreamCoder");
591  }
592 }
593 
594 int64_t
595 StreamCoder::getNextPredictedPts()
596 {
597  return mFakeNextPts;
598 }
599 
600 IRational*
601 StreamCoder::getFrameRate()
602 {
603  if (mCodecContext && mCodecContext->framerate.num > 0) {
604  return Rational::make(&mCodecContext->framerate);
605  }
606  return (mStream ? mStream->getFrameRate() : 0);
607 }
608 
609 void
610 StreamCoder::setFrameRate(IRational* src)
611 {
612  if (mStream && !mOpened)
613  mStream->setFrameRate(src);
614  if (mCodecContext && !mOpened && src){
615  mCodecContext->framerate.den = src->getDenominator();
616  mCodecContext->framerate.num = src->getNumerator();
617  }
618 
619 }
620 
621 int32_t
622 StreamCoder::getNumPicturesInGroupOfPictures()
623 {
624  return (mCodecContext ? mCodecContext->gop_size : -1);
625 }
626 
627 void
628 StreamCoder::setNumPicturesInGroupOfPictures(int32_t val)
629 {
630  if (mCodecContext && !mOpened)
631  mCodecContext->gop_size = val;
632 }
633 
635 StreamCoder::getPixelType()
636 {
637  IPixelFormat::Type retval = IPixelFormat::NONE;
638  int32_t type = 0;
639  if (mCodecContext)
640  {
641  retval = (IPixelFormat::Type) mCodecContext->pix_fmt;
642 
643  // little check here to see if we have an undefined int32_t.
644  type = (int32_t) retval;
645  if (type != mCodecContext->pix_fmt) {
646  VS_LOG_ERROR("Undefined pixel format type: %d", mCodecContext->pix_fmt);
647  retval = IPixelFormat::NONE;
648  }
649  }
650  return retval;
651 }
652 
653 void
654 StreamCoder::setPixelType(IPixelFormat::Type type)
655 {
656  if (mCodecContext && !mOpened)
657  {
658  mCodecContext->pix_fmt = (AVPixelFormat) type;
659  }
660 }
661 
662 int32_t
663 StreamCoder::getSampleRate()
664 {
665  return (mCodecContext ? mCodecContext->sample_rate : -1);
666 }
667 
668 void
669 StreamCoder::setSampleRate(int32_t val)
670 {
671  if (mCodecContext && !mOpened && val > 0)
672  mCodecContext->sample_rate = val;
673 }
674 
676 StreamCoder::getSampleFormat()
677 {
678  return (IAudioSamples::Format) (mCodecContext ? mCodecContext->sample_fmt
679  : -1);
680 }
681 
682 void
683 StreamCoder::setSampleFormat(IAudioSamples::Format val)
684 {
685  if (mCodecContext && !mOpened && val > 0)
686  mCodecContext->sample_fmt = (enum AVSampleFormat) val;
687 }
688 
689 int32_t
690 StreamCoder::getChannels()
691 {
692  return (mCodecContext ? mCodecContext->channels : -1);
693 }
694 
695 void
696 StreamCoder::setChannels(int32_t val)
697 {
698  if (mCodecContext && !mOpened && val > 0)
699  mCodecContext->channels = val;
700 }
701 
702 int32_t
703 StreamCoder::getGlobalQuality()
704 {
705  return (mCodecContext ? mCodecContext->global_quality : FF_LAMBDA_MAX);
706 }
707 
708 void
709 StreamCoder::setGlobalQuality(int32_t newQuality)
710 {
711  if (newQuality < 0 || newQuality > FF_LAMBDA_MAX)
712  newQuality = FF_LAMBDA_MAX;
713  if (mCodecContext)
714  mCodecContext->global_quality = newQuality;
715 }
716 
717 int32_t
718 StreamCoder::getFlags()
719 {
720  return (mCodecContext ? mCodecContext->flags : 0);
721 }
722 
723 void
724 StreamCoder::setFlags(int32_t newFlags)
725 {
726  if (mCodecContext)
727  mCodecContext->flags = newFlags;
728 }
729 
730 bool
731 StreamCoder::getFlag(IStreamCoder::Flags flag)
732 {
733  bool result = false;
734  if (mCodecContext)
735  result = mCodecContext->flags & flag;
736  return result;
737 }
738 
739 void
740 StreamCoder::setFlag(IStreamCoder::Flags flag, bool value)
741 {
742  if (mCodecContext)
743  {
744  if (value)
745  {
746  mCodecContext->flags |= flag;
747  }
748  else
749  {
750  mCodecContext->flags &= (~flag);
751  }
752  }
753 
754 }
755 
756 int32_t
757 StreamCoder::open()
758 {
759  return open(NULL, NULL);
760 }
761 int32_t
762 StreamCoder::open(IMetaData* aOptions, IMetaData* aUnsetOptions)
763 {
764  int32_t retval = -1;
765  AVDictionary* tmp= NULL;
766  try
767  {
768  if (!swrContext)
769  swrContext = swr_alloc();
770  if (!mCodecContext)
771  throw std::runtime_error("no codec context");
772 
773  if (!mCodec)
774  {
775  RefPointer<ICodec> codec = this->getCodec();
776  // This should set mCodec and then release
777  // the local reference.
778  }
779 
780  if (!mCodec)
781  throw std::runtime_error("no codec set for coder");
782 
783  // Time to set options
784  if (aOptions) {
785  MetaData* options = static_cast<MetaData*>(aOptions);
786  if (!options)
787  throw new std::runtime_error("wow... who's passing us crap?");
788 
789  // make a copy of the data returned.
790  av_dict_copy(&tmp, options->getDictionary(), 0);
791  }
792 
793  // don't allow us to open a coder without a time base
794  if (mDirection == ENCODING && mCodecContext->time_base.num == 0)
795  {
796  if (this->getCodecType() == ICodec::CODEC_TYPE_AUDIO)
797  {
798  if (mCodecContext->sample_rate > 0)
799  {
800  mCodecContext->time_base.num = 1;
801  mCodecContext->time_base.den = mCodecContext->sample_rate;
802  }
803  else
804  {
805  throw std::runtime_error("no sample rate set on coder");
806  }
807  }
808  }
809 
810  if (mDirection == ENCODING && this->getCodecType() == ICodec::CODEC_TYPE_AUDIO && !mCodecContext->channel_layout)
811  {
812  mCodecContext->channel_layout = av_get_default_channel_layout(mCodecContext->channels);
813  }
814 
815  // Fix for issue #14: http://code.google.com/p/avpkit/issues/detail?id=14
816  if (mStream)
817  {
818  RefPointer<IContainer> container = mStream->getContainer();
819  if (container)
820  {
821  RefPointer<IContainerFormat> format = container->getContainerFormat();
822  if (format && mDirection == ENCODING && format->getOutputFlag(
823  IContainerFormat::FLAG_GLOBALHEADER))
824  {
825  this->setFlag(FLAG_GLOBAL_HEADER, true);
826  }
827  }
828  }
829 
830  {
831  /*
832  * This is a very annoying bug. FFmpeg will NOT find sub-codec options
833  * if AVCodecContext->codec is not set to a non-null value, but
834  * avcodec_open2 will fail if it is set null. To allow users to set
835  * options easily prior to opening the AVCodecContext, we stash the
836  * value we had been using, and we check after the open call and log
837  * an error if it changed for some reason.
838  */
839  //const AVCodec* cachedCodec = mCodecContext->codec;
840  //mCodecContext->codec = NULL;
841  retval = avcodec_open2(mCodecContext, mCodec->getAVCodec(), &tmp);
842 
843 // if (retval >= 0 && cachedCodec != 0 && cachedCodec != mCodecContext->codec)
844 // {
845 // VS_LOG_ERROR("When opening StreamCoder the codec was changed by FFmpeg. This is not good");
846 // }
847  if (retval < 0)
848  {
849  //mCodecContext->codec = cachedCodec;
850  throw std::runtime_error("could not open codec");
851  }
852  }
853 
854  if (mDirection == ENCODING && mStream) {
855  avcodec_parameters_from_context(mStream->getAVStream()->codecpar, mCodecContext);
856  }
857 
858  mOpened = true;
859 
860  mNumDroppedFrames = 0;
861  mSamplesCoded = mSamplesForEncoding = mLastExternallySetTimeStamp = 0;
862  mFakeCurrPts = mFakeNextPts = mLastPtsEncoded = Global::NO_PTS;
863  for(uint32_t i = 0; i < sizeof(mPtsBuffer)/sizeof(mPtsBuffer[0]); i++)
864  {
865  mPtsBuffer[i] = Global::NO_PTS;
866  }
867 
868  // Do any post open initialization here.
869  if (this->getCodecType() == ICodec::CODEC_TYPE_AUDIO)
870  {
871  int32_t frame_bytes = getAudioFrameSize() * getChannels()
872  * IAudioSamples::findSampleBitDepth(
873  (IAudioSamples::Format) mCodecContext->sample_fmt) / 8;
874  if (frame_bytes <= 0)
875  frame_bytes = 192000; //AVCODEC_MAX_AUDIO_FRAME_SIZE disappear
876 
877  if (!mAudioFrameBuffer || mAudioFrameBuffer->getBufferSize()
878  < frame_bytes)
879  // Re-create it.
880  mAudioFrameBuffer = IBuffer::make(this, frame_bytes);
881  mBytesInFrameBuffer = 0;
882  }
883  if (aUnsetOptions)
884  {
885  MetaData* unsetOptions = static_cast<MetaData*>(aUnsetOptions);
886  if (!unsetOptions)
887  throw std::runtime_error("really... seriously?");
888  unsetOptions->copy(tmp);
889  }
890  }
891  catch (std::bad_alloc & e)
892  {
893  throw e;
894  }
895  catch (std::exception & e)
896  {
897  VS_LOG_WARN("Error: %s", e.what());
898  retval = -1;
899  }
900  if (tmp)
901  av_dict_free(&tmp);
902  return retval;
903 }
904 
905 int32_t
906 StreamCoder::close()
907 {
908  int32_t retval = -1;
909  if (mCodecContext && mOpened)
910  {
911  retval = avcodec_close(mCodecContext);
912  swr_free(&swrContext);
913  mOpened = false;
914  }
915  mBytesInFrameBuffer = 0;
916  return retval;
917 }
918 
919 int32_t
920 StreamCoder::decodeAudio(IAudioSamples *pOutSamples, IPacket *pPacket,
921  int32_t startingByte)
922 {
923  int32_t retval = -1;
924  AudioSamples *samples = static_cast<AudioSamples*> (pOutSamples);
925  Packet* packet = static_cast<Packet*> (pPacket);
926 
927  if (samples)
928  // reset the samples
929  samples->setComplete(false, 0, getSampleRate(), getChannels(),
930  IAudioSamples::FMT_S16, Global::NO_PTS);
931  if (!samples) {
932  VS_LOG_WARN("Attempting to decode when not ready; no samples");
933  return retval;
934  }
935 // if (!packet) {
936 // VS_LOG_WARN("Attempting to decode when not ready; no packet");
937 // return retval;
938 // }
939  if (!mOpened) {
940  VS_LOG_WARN("Attempting to decode when not ready; codec not opened");
941  return retval;
942  }
943  if (!mCodecContext) {
944  VS_LOG_WARN("Attempting to decode when not ready; internal context not allocated");
945  return retval;
946  }
947  if (mDirection != DECODING) {
948  VS_LOG_WARN("Attempting to decode when not ready; StreamCoder is set to encode, not decode");
949  return retval;
950  }
951  if (!mCodec || !mCodec->canDecode()) {
952  VS_LOG_WARN("Attempting to decode when not ready; codec set cannot decode");
953  return retval;
954  }
955  if (getCodecType() != ICodec::CODEC_TYPE_AUDIO) {
956  VS_LOG_WARN("Attempting to decode when not ready; codec set is not an audio codec");
957  return retval;
958  }
959 
960 
961  int outBufSize = 0;
962  int32_t inBufSize = 0;
963 
964  // When decoding with FFMPEG, ffmpeg needs the sample buffer
965  // to be at least this long.
966  samples->ensureCapacity(192000); //AVCODEC_MAX_AUDIO_FRAME_SIZE
967  outBufSize = samples->getMaxBufferSize();
968  if (packet)
969  inBufSize = packet->getSize() - startingByte;
970 
971  if (inBufSize > 0 && outBufSize > 0 || mCodec->getAVCodec()->capabilities & AV_CODEC_CAP_DELAY)
972  {
973 
974  uint8_t * inBuf = 0;
975  uint8_t * outBuf = 0;
976  uint64_t outChannelLayout;
977  AVFrame* frame = av_frame_alloc();
978 
979  if (packet)
980  {
981  RefPointer<IBuffer> buffer = packet->getData();
982  VS_ASSERT(buffer, "no buffer in packet!");
983  if (buffer)
984  inBuf = (uint8_t*) buffer->getBytes(startingByte, inBufSize);
985  VS_ASSERT(inBuf, "no in buffer");
986  }
987 
988  outBuf = (uint8_t*) samples->getRawSamples(0);
989  VS_ASSERT(outBuf, "no out buffer");
990 
991  if (outBuf)
992  {
993  VS_LOG_TRACE("Attempting decodeAudio(%p, %p, %d, %p, %d);",
994  mCodecContext,
995  outBuf,
996  outBufSize,
997  inBuf,
998  inBufSize);
999 
1000  AVPacket pkt;
1001  av_init_packet(&pkt);
1002  pkt.data = NULL;
1003  pkt.size = 0;
1004 
1005  if (inBuf)
1006  {
1007  if (packet && packet->getAVPacket())
1008  pkt = *packet->getAVPacket();
1009  // copy in our buffer
1010  pkt.data = inBuf;
1011  pkt.size = inBufSize;
1012  mCodecContext->reordered_opaque = packet->getPts();
1013  }
1014 
1015 
1016  {
1017 
1018  int got_frame = 0;
1019  retval = avcodec_decode_audio4(mCodecContext, frame, &got_frame, &pkt);
1020 // char ch_layout[64];
1021 // av_get_channel_layout_string(ch_layout,
1022 // sizeof (ch_layout),
1023 // 0,
1024 // frame->channel_layout);
1025 // VS_LOG_ERROR("ch layout: %s", ch_layout);
1026  outChannelLayout = frame->channel_layout;
1027  // the API for decoding audio changed ot support planar audio and we
1028  // need to back-port
1029 
1030 
1031 
1032  if (retval >= 0 && got_frame) {
1033  if (!swr_is_initialized(swrContext)){
1034  swr_alloc_set_opts(swrContext, // we're using an existing context
1035  //av_get_default_channel_layout(av_frame_get_channels(frame)),
1036  frame->channel_layout == 0 ? av_get_default_channel_layout(frame->channels) : frame->channel_layout, // out_ch_layout
1037  AV_SAMPLE_FMT_S16, // out_sample_fmt
1038  frame->sample_rate, // out_sample_rate
1039  //av_frame_get_channel_layout(frame) == 0 ? av_get_default_channel_layout(av_frame_get_channels(frame)) : av_frame_get_channel_layout(frame), // in_ch_layout
1040  frame->channel_layout == 0 ? av_get_default_channel_layout(frame->channels) : frame->channel_layout, // in_ch_layout
1041  mCodecContext->sample_fmt, // in_sample_fmt
1042  frame->sample_rate, // in_sample_rate
1043  0, // log_offset
1044  NULL);
1045  swr_init(swrContext);
1046  }
1047 
1048  int outChannels = av_frame_get_channels(frame);
1049  uint8_t* output[1] = {outBuf};
1050 
1051  int out_samples = swr_convert(swrContext, output, frame->nb_samples, (const uint8_t**)frame->extended_data, frame->nb_samples);
1052  if (out_samples < 0) {
1053  VS_LOG_ERROR("fail to convert samples: %s", Error::make(out_samples)->getDescription());
1054  //av_freep(&output);
1055  return out_samples;
1056  }
1057  int data_size = av_samples_get_buffer_size(NULL,
1058  outChannels,
1059  out_samples,
1060  AV_SAMPLE_FMT_S16,
1061  0);
1062 //
1063 // VS_LOG_DEBUG("Finished %d convertAudio(%p, %d, %d, %d, %d, %d);",
1064 // data_size,
1065 // plane_size,
1066 // mCodecContext,
1067 // out_samples,
1068 // frame->nb_samples,
1069 // av_frame_get_channels(frame),
1070 // outBufSize);
1071 
1072  if (outBufSize < data_size) {
1073  VS_LOG_ERROR("Output buffer is not large enough; no audio actually returned");
1074  outBufSize = 0;
1075  } else {
1076 // memcpy(outBuf, output, data_size);
1077  outBufSize = data_size;
1078 // av_freep(&output);
1079  }
1080  }
1081 
1082  }
1083  VS_LOG_TRACE("Finished %d decodeAudio(%p, %p, %d, %p, %d);",
1084  retval,
1085  mCodecContext,
1086  outBuf,
1087  outBufSize,
1088  inBuf,
1089  inBufSize);
1090  }
1091  if (retval >= 0)
1092  {
1093  // outBufSize is an In-Out parameter
1094  if (outBufSize < 0)
1095  // this can happen for some MPEG decoders
1096  outBufSize = 0;
1097 
1098  IAudioSamples::Format format = IAudioSamples::FMT_S16;
1099  int32_t bytesPerSample = (IAudioSamples::findSampleBitDepth(format) / 8
1100  * getChannels());
1101  int32_t numSamples = outBufSize / bytesPerSample;
1102 
1103  // The audio decoder doesn't set a PTS, so we need to manufacture one.
1104  RefPointer<IRational> timeBase =
1105  this->mStream ? this->mStream->getTimeBase() : 0;
1106  if (!timeBase)
1107  timeBase = this->getTimeBase();
1108 
1109  int64_t packetTs = frame->best_effort_timestamp;
1110 // if (packetTs == Global::NO_PTS)
1111 // packetTs = packet->getDts();
1112 
1113  if (packetTs == Global::NO_PTS && mFakeNextPts == Global::NO_PTS)
1114  {
1115  // the container doesn't have time stamps; assume we start
1116  // at zero
1117  VS_LOG_TRACE("Setting fake pts to 0");
1118  mFakeNextPts = 0;
1119  }
1120  if (packetTs != Global::NO_PTS)
1121  {
1122  // The packet had a valid stream, and a valid time base
1123  if (timeBase->getNumerator() != 0 && timeBase->getDenominator() != 0)
1124  {
1125  int64_t tsDelta = Global::NO_PTS;
1126  if (mFakeNextPts != Global::NO_PTS)
1127  {
1128  int64_t fakeTsInStreamTimeBase = Global::NO_PTS;
1129  // rescale our fake into the time base of stream
1130  fakeTsInStreamTimeBase = timeBase->rescale(mFakeNextPts,
1131  mFakePtsTimeBase.value());
1132  tsDelta = fakeTsInStreamTimeBase - packetTs;
1133  }
1134 
1135  // now, compare it to our internal value; if our internally calculated value
1136  // is within 1 tick of the packet's time stamp (in the packet's time base),
1137  // then we're probably right;
1138  // otherwise, we should reset the stream's fake time stamp based on this
1139  // packet
1140  if (mFakeNextPts != Global::NO_PTS && (tsDelta >= -1 && tsDelta
1141  <= 1))
1142  {
1143  // we're the right value; keep our fake next pts
1144  VS_LOG_TRACE("Keeping mFakeNextPts: %lld", mFakeNextPts);
1145  }
1146  else
1147  {
1148  // rescale to our internal timebase
1149  int64_t packetTsInMicroseconds = mFakePtsTimeBase->rescale(
1150  packetTs, timeBase.value());
1151  VS_LOG_TRACE("%p Gap in audio (%lld); Resetting calculated ts from %lld to %lld",
1152  this,
1153  tsDelta,
1154  mFakeNextPts,
1155  packetTsInMicroseconds);
1156  mLastExternallySetTimeStamp = packetTsInMicroseconds;
1157  mSamplesCoded = 0;
1158  mFakeNextPts = mLastExternallySetTimeStamp;
1159  }
1160  }
1161  }
1162  // Use the last value of the next pts
1163  mFakeCurrPts = mFakeNextPts;
1164  // adjust our next Pts pointer
1165  if (numSamples > 0)
1166  {
1167  mSamplesCoded += numSamples;
1168  mFakeNextPts = mLastExternallySetTimeStamp
1169  + IAudioSamples::samplesToDefaultPts(mSamplesCoded,
1170  getSampleRate());
1171  }
1172 
1173  // copy the packet PTS
1174  samples->setComplete(numSamples > 0, numSamples, getSampleRate(),
1175  getChannels(), (IAudioSamples::ChannelLayout)outChannelLayout, format, mFakeCurrPts);
1176  }
1177 
1178  av_frame_free(&frame);
1179  }
1180 
1181  return retval;
1182 }
1183 
1184 int32_t
1185 StreamCoder::decodeVideo(IVideoPicture *pOutFrame, IPacket *pPacket,
1186  int32_t byteOffset)
1187 {
1188  int32_t retval = -1;
1189  VideoPicture* frame = static_cast<VideoPicture*> (pOutFrame);
1190  Packet* packet = static_cast<Packet*> (pPacket);
1191  if (frame)
1192  // reset the frame
1193  frame->setComplete(false, IPixelFormat::NONE, -1, -1, mFakeCurrPts);
1194 
1195  if (!frame) {
1196  VS_LOG_WARN("Attempting to decode when not ready; no frame");
1197  return retval;
1198  }
1199 // if (!packet) {
1200 // VS_LOG_WARN("Attempting to decode when not ready; no packet");
1201 // return retval;
1202 // }
1203  if (!mOpened) {
1204  VS_LOG_WARN("Attempting to decode when not ready; codec not opened");
1205  return retval;
1206  }
1207  if (!mCodecContext) {
1208  VS_LOG_WARN("Attempting to decode when not ready; internal context not allocated");
1209  return retval;
1210  }
1211  if (mDirection != DECODING) {
1212  VS_LOG_WARN("Attempting to decode when not ready; StreamCoder is set to encode, not decode");
1213  return retval;
1214  }
1215  if (!mCodec || !mCodec->canDecode()) {
1216  VS_LOG_WARN("Attempting to decode when not ready; codec set cannot decode");
1217  return retval;
1218  }
1219  if (getCodecType() != ICodec::CODEC_TYPE_VIDEO) {
1220  VS_LOG_WARN("Attempting to decode when not ready; codec set is not a video codec");
1221  return retval;
1222  }
1223 
1224  AVFrame *avFrame = av_frame_alloc();
1225  if (avFrame)
1226  {
1227  int frameFinished = 0;
1228  int32_t inBufSize = 0;
1229  uint8_t * inBuf = 0;
1230  if (packet) {
1231  RefPointer<IBuffer> buffer = packet->getData();
1232  inBufSize = packet->getSize() - byteOffset;
1233 
1234  VS_ASSERT(buffer, "no buffer in packet?");
1235  if (buffer)
1236  inBuf = (uint8_t*) buffer->getBytes(byteOffset, inBufSize);
1237 
1238  VS_ASSERT(inBuf, "incorrect size or no data in packet");
1239  }
1240 
1241  if (inBufSize > 0 && inBuf || mCodec->getAVCodec()->capabilities & AV_CODEC_CAP_DELAY)
1242  {
1243  AVPacket pkt;
1244  av_init_packet(&pkt);
1245  pkt.data = NULL;
1246  pkt.size = 0;
1247 
1248  if (inBuf) {
1249  VS_LOG_TRACE("Attempting decodeVideo(%p, %p, %d, %p, %d);",
1250  mCodecContext,
1251  avFrame,
1252  frameFinished,
1253  inBuf,
1254  inBufSize);
1255  if (packet && packet->getAVPacket())
1256  pkt = *packet->getAVPacket();
1257  pkt.data = inBuf;
1258  pkt.size = inBufSize;
1259  }
1260  //mCodecContext->reordered_opaque = packet->getPts();
1261  retval = avcodec_decode_video2(mCodecContext, avFrame, &frameFinished,
1262  &pkt);
1263  VS_LOG_TRACE("Finished %d decodeVideo(%p, %p, %d, %p, %d);",
1264  retval,
1265  mCodecContext,
1266  avFrame,
1267  frameFinished,
1268  inBuf,
1269  inBufSize);
1270 
1271  if (retval >= 0)
1272  {
1273 
1274  if (frameFinished)
1275  {
1276  // copy FFMPEG's buffer into our buffer; don't try to get efficient
1277  // and reuse the buffer FFMPEG is using; in order to allow our
1278  // buffers to be thread safe, we must do a copy here.
1279  avFrame->hw_frames_ctx = mCodecContext->hw_frames_ctx;
1280  frame->copyAVFrame(avFrame, getPixelType(), getWidth(), getHeight());
1281  RefPointer<IRational> timeBase = 0;
1282  timeBase = this->mStream ? this->mStream->getTimeBase() : 0;
1283  if (!timeBase)
1284  timeBase = this->getTimeBase();
1285 
1286  int64_t packetTs = avFrame->best_effort_timestamp;
1287 
1288  if (packetTs != Global::NO_PTS)
1289  {
1290  if (timeBase->getNumerator() != 0)
1291  {
1292  // The decoder set a PTS, so we let it override us
1293  int64_t nextPts = mFakePtsTimeBase->rescale(packetTs,
1294  timeBase.value());
1295  // some youtube videos incorrectly return a packet
1296  // with the wrong re-ordered opaque setting. this
1297  // detects that and uses the PTS from the packet instead.
1298  // See: http://code.google.com/p/avpkit/issues/detail?id=165
1299  // in this way we enforce that timestamps are always
1300  // increasing
1301  // if (avFrame->reordered_opaque != Global::NO_PTS && nextPts < mFakeNextPts && packet->getPts() != Global::NO_PTS) {
1302  // VS_LOG_WARN("Bad order in pts packet pts will be used instead of frame pts (packetTs: %ld, reordered_opaque: %ld, nextPts: %ld, mFakeNextPts: %ld, packet pts: %ld)",
1303  // packetTs,
1304  // avFrame->reordered_opaque,
1305  // nextPts,
1306  // mFakeNextPts,
1307  // packet->getPts());
1308  // nextPts = mFakePtsTimeBase->rescale(packet->getPts(),
1309  // timeBase.value());
1310  // }
1311  mFakeNextPts = nextPts;
1312  }
1313  }
1314 
1315  // Use the last value of the next pts
1316  mFakeCurrPts = mFakeNextPts;
1317  double frameDelay = av_rescale(timeBase->getNumerator(),
1318  AV_TIME_BASE, timeBase->getDenominator());
1319  frameDelay += avFrame->repeat_pict * (frameDelay * 0.5);
1320 
1321  // adjust our next Pts pointer
1322  mFakeNextPts += (int64_t) frameDelay;
1323  // VS_LOG_DEBUG("frame complete: %s; pts: %lld; packet ts: %lld; opaque ts: %lld; tb: %ld/%ld",
1324  // (frameFinished ? "yes" : "no"),
1325  // mFakeCurrPts,
1326  // (packet ? packet->getDts() : 0),
1327  // packetTs,
1328  // timeBase->getNumerator(),
1329  // timeBase->getDenominator()
1330  // );
1331  }
1332  frame->setComplete(frameFinished, this->getPixelType(),
1333  this->getWidth(), this->getHeight(), mFakeCurrPts);
1334 
1335  }
1336  }
1337  av_frame_free(&avFrame);
1338  }
1339 
1340  return retval;
1341 }
1342 
1343 int32_t
1344 StreamCoder::encodeVideo(IPacket *pOutPacket, IVideoPicture *pFrame,
1345  int32_t suggestedBufferSize)
1346 {
1347  int32_t retval = -1;
1348  VideoPicture *frame = static_cast<VideoPicture*> (pFrame);
1349  Packet *packet = static_cast<Packet*> (pOutPacket);
1350  RefPointer<IBuffer> encodingBuffer;
1351 
1352  try
1353  {
1354  if (packet)
1355  packet->reset();
1356 
1357  if (getCodecType() != ICodec::CODEC_TYPE_VIDEO)
1358  throw std::runtime_error(
1359  "Attempting to encode video with non video coder");
1360 
1361  if (frame && frame->getPixelType() != this->getPixelType())
1362  throw std::runtime_error(
1363  "picture is not of the same PixelType as this Coder expected");
1364  if (frame && frame->getWidth() != this->getWidth())
1365  throw std::runtime_error("picture is not of the same width as this Coder");
1366  if (frame && frame->getHeight() != this->getHeight())
1367  throw std::runtime_error(
1368  "picture is not of the same height as this Coder");
1369 
1370  if (mDirection != ENCODING)
1371  throw std::runtime_error("Decoding StreamCoder not valid for encoding");
1372  if (!mCodec)
1373  throw std::runtime_error("Codec not set");
1374  if (!mCodec->canEncode())
1375  throw std::runtime_error("Codec cannot be used to encode");
1376  if (mCodecContext && mOpened && mDirection == ENCODING && packet)
1377  {
1378  uint8_t* buf = 0;
1379  int32_t bufLen = 0;
1380 
1381  // First, get the right buffer size.
1382  if (suggestedBufferSize <= 0)
1383  {
1384  if (frame)
1385  {
1386  suggestedBufferSize = frame->getSize();
1387  }
1388  else
1389  {
1390  suggestedBufferSize = av_image_get_buffer_size(
1391  (AVPixelFormat) getPixelType(), getWidth(), getHeight(), 1);
1392  }
1393  }
1394  VS_ASSERT(suggestedBufferSize> 0, "no buffer size in input frame");
1395  suggestedBufferSize = FFMAX(suggestedBufferSize, AV_INPUT_BUFFER_MIN_SIZE);
1396 
1397  retval = packet->allocateNewPayload(suggestedBufferSize);
1398  if (retval >= 0)
1399  {
1400  encodingBuffer = packet->getData();
1401  }
1402  if (encodingBuffer)
1403  {
1404  buf = (uint8_t*) encodingBuffer->getBytes(0, suggestedBufferSize);
1405  bufLen = encodingBuffer->getBufferSize();
1406  }
1407 
1408  if (buf && bufLen || mCodec->getAVCodec()->capabilities & AV_CODEC_CAP_DELAY)
1409  {
1410  // Change the PTS in our frame to the timebase of the encoded stream
1411  RefPointer<IRational> thisTimeBase = getTimeBase();
1412 
1413  /*
1414  * We make a copy of the AVFrame object and explicitly copy
1415  * over the values that we know encoding cares about.
1416  *
1417  * This is because often some programs decode into an VideoPicture
1418  * and just want to pass that to encodeVideo. If we just
1419  * leave the values that Ffmpeg had in the AVFrame during
1420  * decoding, strange errors can result.
1421  *
1422  * Plus, this forces us to KNOW what we're passing into the encoder.
1423  */
1424  AVFrame* avFrame = 0;
1425  bool dropFrame = false;
1426  if (frame)
1427  {
1428  avFrame = av_frame_alloc();
1429  if (!avFrame)
1430  throw std::bad_alloc();
1431  frame->fillAVFrame(avFrame);
1432 
1433  // convert into the time base that this coder wants
1434  // to output in
1435  int64_t codecTimeBasePts = thisTimeBase->rescale(frame->getPts(),
1436  mFakePtsTimeBase.value(), IRational::ROUND_DOWN);
1437  if (mLastPtsEncoded != Global::NO_PTS)
1438  {
1439  // adjust for rounding;
1440  // fixes http://code.google.com/p/avpkit/issues/detail?id=180
1441  if (codecTimeBasePts < mLastPtsEncoded)
1442  {
1443  VS_LOG_TRACE(
1444  "Dropping frame with timestamp %lld (if coder supports higher time-base use that instead)",
1445  frame->getPts());
1446  dropFrame = true;
1447  }
1448  else if (codecTimeBasePts == mLastPtsEncoded)
1449  {
1450  // else we're close enough; increment by 1
1451  ++codecTimeBasePts;
1452  }
1453  }
1454  VS_LOG_TRACE("Rescaling ts: %lld to %lld (last: %lld) (from base %d/%d to %d/%d)",
1455  frame->getPts(),
1456  codecTimeBasePts,
1457  mLastPtsEncoded,
1458  mFakePtsTimeBase->getNumerator(),
1459  mFakePtsTimeBase->getDenominator(),
1460  thisTimeBase->getNumerator(),
1461  thisTimeBase->getDenominator());
1462  avFrame->pts = codecTimeBasePts;
1463  if (!dropFrame)
1464  mLastPtsEncoded = avFrame->pts;
1465  }
1466 
1467  int got_pkt;
1468 
1469  if (!dropFrame)
1470  {
1471  VS_LOG_TRACE("Attempting encodeVideo(%p, %p, %d, %p)",
1472  mCodecContext,
1473  buf,
1474  bufLen,
1475  avFrame);
1476  packet->getAVPacket()->size = suggestedBufferSize;
1477  retval = avcodec_encode_video2(mCodecContext, packet->getAVPacket(), avFrame, &got_pkt);
1478 // retval = avcodec_encode_video(mCodecContext, buf, bufLen, avFrame);
1479 
1480  }
1481  else
1482  {
1483  ++mNumDroppedFrames;
1484  retval = 0;
1485  }
1486  if (retval == 0)
1487  {
1488  int64_t dts = (avFrame ? mLastPtsEncoded : mLastPtsEncoded + 1);
1489  int64_t duration = 1;
1490  if (got_pkt) {
1491  int32_t num = thisTimeBase->getNumerator();
1492  int32_t den = thisTimeBase->getDenominator();
1493  if (num*1000LL > den)
1494  {
1495  if (mCodecContext->coded_frame
1496  && mCodecContext->coded_frame->repeat_pict)
1497  {
1498  num = num * (1+mCodecContext->coded_frame->repeat_pict);
1499  }
1500  }
1501  duration = av_rescale(1,
1502  num * (int64_t)den * mCodecContext->ticks_per_frame,
1503  den * (int64_t) thisTimeBase->getNumerator());
1504 
1505  // This will be zero if the Codec does not use b-frames;
1506  // although we provide space for delaying up to the
1507  // max H264 delay, in reality we only need delay by 1 tick.
1508  int32_t delay = FFMAX(mCodecContext->has_b_frames,
1509  mCodecContext->max_b_frames > 0);
1510  dts = packet->getAVPacket()->dts;
1511  if (packet->getAVPacket()->pts != Global::NO_PTS && dts == Global::NO_PTS && delay <= MAX_REORDER_DELAY)
1512  {
1513  int64_t pts = packet->getAVPacket()->pts;
1514  mPtsBuffer[0] = pts;
1515  int32_t i;
1516  // If first time through set others to some 'sensible' defaults.
1517  // If the first PTS is zero, this leads to starting negative
1518  // dts values, but FFmpeg allows that so we do too.
1519  for(i = 1; i < delay + 1 && mPtsBuffer[i] == Global::NO_PTS; i++)
1520  mPtsBuffer[i] = pts + (i-delay-1)*duration;
1521  // Order the PTS values in increasing order and the lowest
1522  // one will magically be the DTS we should use for this packet.
1523  for(i = 0; i < delay && mPtsBuffer[i] > mPtsBuffer[i+1]; i++)
1524  FFSWAP(int64_t, mPtsBuffer[i], mPtsBuffer[i+1]);
1525  dts = mPtsBuffer[0];
1526 // VS_LOG_ERROR("type: %d; output: dts: %lld; pts: %lld",
1527 // mCodecContext->coded_frame->pict_type,
1528 // dts,
1529 // pts);
1530  }
1531  }
1532  setPacketParameters(
1533  packet,
1534  got_pkt ? packet->getAVPacket()->size : retval,
1535  // if the last packet, increment the pts encoded
1536  // by one
1537  dts,
1538  thisTimeBase.value(),
1539  (packet->getAVPacket()->flags & AV_PKT_FLAG_KEY), duration, got_pkt);
1540  }
1541  if (avFrame)
1542  av_free(avFrame);
1543  }
1544  }
1545  else
1546  {
1547  VS_LOG_WARN("Attempting to encode when not ready");
1548  }
1549  }
1550  catch (std::bad_alloc & e)
1551  {
1552  retval = -1;
1553  throw e;
1554  }
1555  catch (std::exception & e)
1556  {
1557  VS_LOG_WARN("Got error: %s", e.what());
1558  retval = -1;
1559  }
1560 
1561  return retval;
1562 }
1563 
1564 int32_t
1565 StreamCoder::encodeAudio(IPacket * pOutPacket, IAudioSamples* pSamples,
1566  int32_t startingSample)
1567 {
1568  int32_t retval = -1;
1569  AudioSamples *samples = static_cast<AudioSamples*> (pSamples);
1570  Packet *packet = static_cast<Packet*> (pOutPacket);
1571  RefPointer<IBuffer> encodingBuffer;
1572  bool usingInternalFrameBuffer = false;
1573 
1574  try
1575  {
1576  if (mDirection != ENCODING)
1577  throw std::runtime_error("Decoding StreamCoder not valid for encoding");
1578  if (!mCodec)
1579  throw std::runtime_error("Codec not set");
1580  if (!mCodec->canEncode()) {
1581  std::string msg = "Codec cannot be used to encode: ";
1582  msg += mCodec->getName();
1583  throw std::runtime_error(msg);
1584  }
1585  if (!packet)
1586  throw std::invalid_argument("Invalid packet to encode to");
1587  // Zero out our packet
1588  packet->reset();
1589 
1590  if (!mCodecContext)
1591  throw std::runtime_error("StreamCoder not initialized properly");
1592  if (!mOpened)
1593  throw std::runtime_error("StreamCoder not open");
1594  if (getCodecType() != ICodec::CODEC_TYPE_AUDIO)
1595  throw std::runtime_error(
1596  "Attempting to encode audio with non audio coder");
1597  if (!mAudioFrameBuffer)
1598  throw std::runtime_error("Audio Frame Buffer not initialized");
1599 
1600  // First, how many bytes do we need to encode a packet?
1601  int32_t frameSize = 0;
1602  int32_t frameBytes = 0;
1603  int32_t availableSamples = (samples ? samples->getNumSamples()
1604  - startingSample : 0);
1605  int32_t samplesConsumed = 0;
1606  short *avSamples = (samples ? samples->getRawSamples(startingSample) : 0);
1607 
1608  if (samples)
1609  {
1610  if (samples->getChannels() != getChannels())
1611  throw std::invalid_argument(
1612  "channels in sample do not match StreamCoder");
1613  if (samples->getSampleRate() != getSampleRate())
1614  throw std::invalid_argument(
1615  "sample rate in sample does not match StreamCoder");
1616 
1617  if (!samples->isComplete())
1618  throw std::invalid_argument("input samples are not complete");
1619 
1620  if (mFakeNextPts == Global::NO_PTS && samples->getTimeStamp()
1621  != Global::NO_PTS)
1622  mFakeNextPts = samples->getTimeStamp()
1623  + IAudioSamples::samplesToDefaultPts(startingSample,
1624  getSampleRate());
1625 
1626  }
1627 
1628  if (mFakeNextPts == Global::NO_PTS)
1629  mFakeNextPts = 0;
1630 
1631  if (availableSamples < 0 || (avSamples && availableSamples == 0))
1632  throw std::invalid_argument(
1633  "no bytes in buffer at specified starting sample");
1634 
1635  int32_t bytesPerSample = (samples ? samples->getSampleSize()
1636  : IAudioSamples::findSampleBitDepth(
1637  (IAudioSamples::FMT_S16)) / 8
1638  * getChannels());
1639 
1640  /*
1641  * This gets tricky; There may be more audio samples passed to
1642  * us than can fit in an audio frame, or there may be less.
1643  *
1644  * If less, we need to cache for a future call.
1645  *
1646  * If more, we need to just use what's needed, and let the caller
1647  * know the number of samples we used.
1648  *
1649  * What happens when we exhaust all audio, but we still don't
1650  * have enough to decode a frame? answer: the caller passes us
1651  * NULL as the pInSamples, and we just silently drop the incomplete
1652  * frame.
1653  *
1654  * To simplify coding here (and hence open for optimization if
1655  * this ends up being a bottleneck), I always copy audio samples
1656  * into a frame buffer, and then only encode from the frame buffer
1657  * in this class.
1658  */
1659  frameSize = getAudioFrameSize();
1660  frameBytes = frameSize * bytesPerSample;
1661 
1662  // More error checking
1663  VS_ASSERT(frameBytes <= mAudioFrameBuffer->getBufferSize(),
1664  "did frameSize change from open?");
1665  if (frameBytes > mAudioFrameBuffer->getBufferSize())
1666  throw std::runtime_error("not enough memory in internal frame buffer");
1667 
1668  VS_ASSERT(mBytesInFrameBuffer <= frameBytes,
1669  "did frameSize change from open?");
1670  if (frameBytes < mBytesInFrameBuffer)
1671  throw std::runtime_error(
1672  "too many bytes left over in internal frame buffer");
1673 
1674  uint8_t * frameBuffer = (uint8_t*) mAudioFrameBuffer->getBytes(
1675  0, frameBytes);
1676  if (!frameBuffer)
1677  throw std::runtime_error("could not get internal frame buffer");
1678 
1679  int32_t bytesToCopyToFrameBuffer = frameBytes - mBytesInFrameBuffer;
1680  bytesToCopyToFrameBuffer = FFMIN(bytesToCopyToFrameBuffer,
1681  availableSamples*bytesPerSample);
1682 
1683  uint8_t *convertAvSamples;
1684 
1685  if (avSamples)
1686  {
1687  if (availableSamples >= frameSize && mBytesInFrameBuffer == 0)
1688  { //TODO: gerer CODEC_CAP_VARIABLE_FRAME_SIZE CODEC_CAP_SMALL_LAST_FRAME
1689  VS_LOG_TRACE("audioEncode: Using passed in buffer: %d, %d, %d",
1690  availableSamples, frameSize, mBytesInFrameBuffer);
1691  frameBuffer = (uint8_t*)avSamples;
1692  samplesConsumed = frameSize;
1693  usingInternalFrameBuffer = false;
1694  }
1695  else
1696  {
1697  VS_LOG_TRACE("audioEncode: Using internal buffer: %d, %d, %d %d %d",
1698  availableSamples, frameSize, mBytesInFrameBuffer);
1699  if (bytesToCopyToFrameBuffer != 0){
1700  memcpy(frameBuffer + mBytesInFrameBuffer, avSamples, bytesToCopyToFrameBuffer);
1701  mBytesInFrameBuffer += bytesToCopyToFrameBuffer;
1702  }
1703  samplesConsumed = bytesToCopyToFrameBuffer / bytesPerSample;
1704  retval = samplesConsumed;
1705  usingInternalFrameBuffer = true;
1706 
1707  }
1708 
1709  if (mPtsOfFrameBuffer == Global::NO_PTS) {
1710  RefPointer<IRational> thisTimeBase = getTimeBase();
1711  mPtsOfFrameBuffer = thisTimeBase->rescale(samples->getTimeStamp() + IAudioSamples::samplesToDefaultPts(startingSample, samples->getSampleRate()), mFakePtsTimeBase.value());
1712  }
1713  }
1714  else
1715  {
1716  // drop everything in the frame buffer, and instead
1717  // just pass a null buffer to the encoder.
1718 
1719  // this should happen when the caller passes NULL for the
1720  // input samples
1721  frameBuffer = NULL;
1722  }
1723  mSamplesForEncoding += samplesConsumed;
1724  VS_LOG_TRACE("Consumed %ld for total of %lld Need %d got %d",
1725  samplesConsumed, mSamplesForEncoding, frameBytes, mBytesInFrameBuffer);
1726 
1727  if (!frameBuffer || !usingInternalFrameBuffer || mBytesInFrameBuffer
1728  >= frameBytes)
1729  {
1730  // First, get the right buffer size.
1731  int32_t bufferSize = frameBytes;
1732  if (mCodecContext->codec->id == AV_CODEC_ID_FLAC
1733  || mCodecContext->codec->id == AV_CODEC_ID_VORBIS)
1734  {
1735  // FLAC & VORBIS audio for some reason gives an error if your output buffer isn't
1736  // over double the frame size, so we fake it here. This could be further optimized
1737  // to only require an exact number, but this math is simpler and will always
1738  // be large enough.
1739  bufferSize = (64 + getAudioFrameSize() * (bytesPerSample + 1)) * 2;
1740  }
1741  VS_ASSERT(bufferSize> 0, "no buffer size in samples");
1742  retval = packet->allocateNewPayload(bufferSize);
1743  if (retval >= 0)
1744  {
1745  encodingBuffer = packet->getData();
1746  }
1747 
1748  uint8_t* buf = 0;
1749 
1750  if (encodingBuffer)
1751  {
1752  buf = (uint8_t*) encodingBuffer->getBytes(0, bufferSize);
1753  }
1754  if (buf && bufferSize)
1755  {
1756  VS_LOG_TRACE("Attempting encodeAudio(%p, %p, %d, %p)",
1757  mCodecContext,
1758  buf,
1759  bufferSize,
1760  frameBuffer);
1761 
1762  // This hack works around the fact that PCM's codecs
1763  // calculate samples from buffer length, and sets
1764  // the wrong frame size, but in
1765  // reality we're always passing in 2 byte samples.
1766  // TODO :delete if not necessary
1767 // double pcmCorrection = 1.0;
1768 // switch (mCodecContext->codec->id)
1769 // {
1770 // case AV_CODEC_ID_PCM_S32LE:
1771 // case AV_CODEC_ID_PCM_S32BE:
1772 // case AV_CODEC_ID_PCM_U32LE:
1773 // case AV_CODEC_ID_PCM_U32BE:
1774 // pcmCorrection = 2.0;
1775 // break;
1776 // case AV_CODEC_ID_PCM_S24LE:
1777 // case AV_CODEC_ID_PCM_S24BE:
1778 // case AV_CODEC_ID_PCM_U24LE:
1779 // case AV_CODEC_ID_PCM_U24BE:
1780 // case AV_CODEC_ID_PCM_S24DAUD:
1781 // pcmCorrection = 1.5;
1782 // break;
1783 // case AV_CODEC_ID_PCM_S16LE:
1784 // case AV_CODEC_ID_PCM_S16BE:
1785 // case AV_CODEC_ID_PCM_U16LE:
1786 // case AV_CODEC_ID_PCM_U16BE:
1787 // pcmCorrection = 1.0;
1788 // break;
1789 // case AV_CODEC_ID_PCM_ALAW:
1790 // case AV_CODEC_ID_PCM_MULAW:
1791 // case AV_CODEC_ID_PCM_S8:
1792 // case AV_CODEC_ID_PCM_U8:
1793 // case AV_CODEC_ID_PCM_ZORK:
1794 // pcmCorrection = 0.5;
1795 // break;
1796 // default:
1797 // pcmCorrection = 1.0;
1798 // }
1799 
1800  int size = 0;
1801  int got_packet;
1802  AVPacket pkt;
1803  av_init_packet(&pkt);
1804  pkt.data = NULL;
1805  pkt.size = 0;
1806 
1807  if(!pSamples){
1808  retval = avcodec_encode_audio2(mCodecContext, &pkt, NULL, &got_packet);
1809  }else{
1810  int ret = 0;
1811  if (!swr_is_initialized(swrContext)){
1812  swr_alloc_set_opts(swrContext, // we're using existing context
1813  (int64_t)samples->getChannelLayout(), // out_ch_layout
1814  mCodecContext->sample_fmt, // out_sample_fmt
1815  samples->getSampleRate(), // out_sample_rate
1816  (int64_t)samples->getChannelLayout(), // in_ch_layout
1817  AV_SAMPLE_FMT_S16, // in_sample_fmt
1818  samples->getSampleRate(), // in_sample_rate
1819  0, // log_offset
1820  NULL);
1821  swr_init(swrContext);
1822  }
1823 
1824 
1825  AVFrame* codingFrame = av_frame_alloc();
1826  codingFrame->nb_samples = frameSize;
1827  codingFrame->format = mCodecContext->sample_fmt;
1828  codingFrame->channel_layout = (uint64_t)samples->getChannelLayout();
1829 
1830  if (samples->getPts() != Global::NO_PTS) {
1831  codingFrame->pts = mPtsOfFrameBuffer;
1832  }
1833 
1834 
1835 
1836  retval = av_frame_get_buffer(codingFrame, 0);
1837  if (retval<0){
1838  printf("Error %s",Error::make(retval)->getDescription());
1839  av_frame_free(&codingFrame);
1840  throw std::bad_alloc();
1841  }
1842 
1843  ret = swr_convert(swrContext, codingFrame->extended_data, frameSize, (const uint8_t**) &frameBuffer, frameSize);
1844  if (ret < 0) {
1845  VS_LOG_ERROR("fail to convert samples: %s", Error::make(ret)->getDescription());
1846  av_freep(&convertAvSamples);
1847  throw std::runtime_error("fail to convert samples");
1848  }
1849  VS_LOG_TRACE("Finished %d convertAudio(%p, %d, %d, %d, %d, %d);",
1850  ret,
1851  swrContext,
1852  availableSamples > frameSize ? frameSize : availableSamples,
1853  samples->getNumSamples(),
1854  frameSize);
1855 
1856  retval = avcodec_encode_audio2(mCodecContext, &pkt, codingFrame, &got_packet);
1857  av_frame_free(&codingFrame);
1858  }
1859 
1860  if (retval>=0 && got_packet){
1861  packet->wrapAVPacket(&pkt);
1862  size = packet->getSize();
1863  av_packet_unref(&pkt);
1864  }
1865 
1866  VS_LOG_TRACE("Finished %d %d encodeAudio(%d, %p, %d, %d, %p)",
1867  retval,
1868  got_packet,
1869  size,
1870  mCodecContext,
1871  samplesConsumed,
1872  /*buf,*/
1873  bufferSize,
1874  frameBuffer);
1875  // regardless of what happened, nuke any data in our frame
1876  // buffer.
1877  mBytesInFrameBuffer = 0;
1878  mPtsOfFrameBuffer = Global::NO_PTS;
1879  if (retval >= 0)
1880  {
1881  // and only do this if a packet is returned
1882  if (retval >= 0 && got_packet)
1883  {
1884 
1885  mSamplesCoded += frameSize;
1886 
1887  // let's check to see if the time stamp of passed in
1888  // samples (if any) are within tolerance of our expected
1889  // time stamp. if not, this is most likely happening
1890  // because the IStreamCoder's data source lost a packet.
1891  // We will adjust our starting time stamps then for this new
1892  // packet
1893  mFakeCurrPts = mFakeNextPts;
1894  if (samples && samples->getTimeStamp() != Global::NO_PTS)
1895  {
1896  int64_t samplesTs = samples->getTimeStamp()
1897  + IAudioSamples::samplesToDefaultPts(startingSample
1898  + samplesConsumed, getSampleRate());
1899  int64_t samplesCached = mSamplesForEncoding - mSamplesCoded;
1900  int64_t tsDelta = IAudioSamples::samplesToDefaultPts(
1901  samplesCached, getSampleRate());
1902  int64_t gap = samplesTs - (mFakeNextPts + tsDelta);
1903 
1904  // ignore negative gaps; some containers like WMV
1905  // don't actually set the right time stamps, and we
1906  // can assume a negative gap can't happen
1907  if ((gap > 1))
1908  {
1909  VS_LOG_TRACE("reset;"
1910  "samplesTs:%lld;"
1911  "samplesConsumed:%ld;"
1912  "startingSample:%lu;"
1913  "samplesForEncoding:%lld;"
1914  "samplesCoded:%lld;"
1915  "samplesCached:%lld;"
1916  "tsDelta:%lld;"
1917  "fakeNextPts:%lld;"
1918  "gap:%lld;"
1919  "lastExternallySetTs:%lld;"
1920  "new fakeNextPts:%lld;",
1921  samplesTs,
1922  samplesConsumed,
1923  startingSample,
1924  mSamplesForEncoding,
1925  mSamplesCoded,
1926  samplesCached,
1927  tsDelta,
1928  mFakeNextPts,
1929  gap,
1930  mLastExternallySetTimeStamp,
1931  samplesTs - tsDelta);
1932  mLastExternallySetTimeStamp = samplesTs - tsDelta;
1933  mSamplesCoded = 0;
1934  mSamplesForEncoding = samplesCached;
1935  }
1936  }
1937  mFakeNextPts = mLastExternallySetTimeStamp
1938  + IAudioSamples::samplesToDefaultPts(mSamplesCoded,
1939  getSampleRate());
1940 
1941  }
1942  RefPointer<IRational> thisTimeBase = getTimeBase();
1943  int64_t ts;
1944  int64_t duration = IAudioSamples::samplesToDefaultPts(frameSize,
1945  getSampleRate());
1946  if (!thisTimeBase)
1947  {
1948  thisTimeBase.reset(mFakePtsTimeBase.value(), true);
1949  ts = mFakeCurrPts;
1950  }
1951  else
1952  {
1953  ts = thisTimeBase->rescale(mFakeCurrPts, mFakePtsTimeBase.value());
1954  duration
1955  = thisTimeBase->rescale(duration, mFakePtsTimeBase.value());
1956  }
1957  setPacketParameters(packet, size, ts, thisTimeBase.value(), true,
1958  duration, got_packet);
1959  //printf("%d\n",(int)ts);
1960  // setPacketParameters(packet, size, packet->getAVPacket()->dts, thisTimeBase.value(), true,
1961 // packet->getAVPacket()->duration);
1962 
1963  retval = samplesConsumed;
1964  }
1965  else
1966  {
1967  throw std::runtime_error("avcodec_encode_audio failed");
1968  }
1969  }
1970  }
1971  }
1972  catch (std::bad_alloc & e)
1973  {
1974  throw e;
1975  }
1976  catch (std::exception& e)
1977  {
1978  VS_LOG_WARN("error: %s", e.what());
1979  retval = -1;
1980  }
1981 
1982  return retval;
1983 }
1984 
1985 void
1986 StreamCoder::setPacketParameters(Packet * packet, int32_t size, int64_t dts,
1987  IRational *timebase, bool keyframe, int64_t duration, bool complete)
1988 {
1989  packet->setDuration(duration);
1990 
1991  // VS_LOG_DEBUG("input: dts: %lld; pts: %lld",
1992  // dts,
1993  // mCodecContext->coded_frame ? mCodecContext->coded_frame->pts : Global::NO_PTS);
1994 
1995 
1996  int64_t pts = dts;
1997 
1998  if (packet->getAVPacket()->pts != Global::NO_PTS)
1999  {
2000  RefPointer<IRational> coderBase = getTimeBase();
2001  pts = timebase->rescale(packet->getAVPacket()->pts, coderBase.value());
2002  }
2003  if (pts == Global::NO_PTS)
2004  pts = dts;
2005 
2006  if (pts != Global::NO_PTS && (dts == Global::NO_PTS || dts > pts))
2007  // if our pts is earlier than what we think our decode time stamp should
2008  // be, well, then adjust the decode timestamp. We should ALWAYS
2009  // honor PTS if set
2010  dts = pts;
2011 
2012  packet->setKeyPacket(keyframe);
2013  packet->setPts(pts);
2014  packet->setDts(dts);
2015  packet->setStreamIndex(-1);
2016  packet->setTimeBase(timebase);
2017  // We will sometimes encode some data, but have zero data to send.
2018  // in that case, mark the packet as incomplete so people don't
2019  // output it.
2020  packet->setComplete(complete, size);
2021 
2022  if (mStream)
2023  {
2024  packet->setStreamIndex(mStream->getIndex());
2025  // VS_LOG_DEBUG("use AutomaticallyStampPacketsForStream: %d", mAutomaticallyStampPacketsForStream);
2026 
2027  if (mAutomaticallyStampPacketsForStream)
2028  mStream->stampOutputPacket(packet);
2029  }
2030 
2031  VS_LOG_TRACE("Encoded packet; size: %d; pts: %lld", size, pts);
2032 }
2033 
2034 int32_t
2035 StreamCoder::getAudioFrameSize()
2036 {
2037  int32_t retval = 0;
2038  if (mCodec && mCodec->getType() == ICodec::CODEC_TYPE_AUDIO)
2039  {
2040  if (mCodecContext->frame_size <= 1)
2041  {
2042  // Rats; some PCM encoders give a frame size of 1, which is too
2043  //small. We pick a more sensible value.
2044  retval = getDefaultAudioFrameSize();
2045  }
2046  else
2047  {
2048  retval = mCodecContext->frame_size;
2049  }
2050  }
2051  return retval;
2052 }
2053 
2054 int32_t
2055 StreamCoder::streamClosed(Stream*stream)
2056 {
2057  int32_t retval = 0;
2058  if (stream == mStream)
2059  {
2060  reset();
2061  }
2062  return retval;
2063 }
2064 
2065 // For ref-count debugging purposes.
2066 int32_t
2067 StreamCoder::acquire()
2068 {
2069  int32_t retval = 0;
2070  retval = RefCounted::acquire();
2071  VS_LOG_TRACE("Acquired %p: %d", this, retval);
2072  return retval;
2073 }
2074 
2075 int32_t
2076 StreamCoder::release()
2077 {
2078  int32_t retval = 0;
2079  retval = RefCounted::release();
2080  VS_LOG_TRACE("Released %p: %d", this, retval);
2081  return retval;
2082 }
2083 
2084 int32_t
2085 StreamCoder::getCodecTag()
2086 {
2087  return (mCodecContext ? mCodecContext->codec_tag : 0);
2088 }
2089 
2090 void
2091 StreamCoder::setCodecTag(int32_t tag)
2092 {
2093  if (mCodecContext)
2094  mCodecContext->codec_tag = tag;
2095 }
2096 
2097 int32_t
2098 StreamCoder::getNumProperties()
2099 {
2100  return Property::getNumProperties(mCodecContext);
2101 }
2102 
2103 IProperty*
2104 StreamCoder::getPropertyMetaData(int32_t propertyNo)
2105 {
2106  return Property::getPropertyMetaData(mCodecContext, propertyNo);
2107 }
2108 
2109 IProperty*
2110 StreamCoder::getPropertyMetaData(const char *name)
2111 {
2112  return Property::getPropertyMetaData(mCodecContext, name);
2113 }
2114 
2115 int32_t
2116 StreamCoder :: setProperty(IMetaData* valuesToSet, IMetaData* valuesNotFound)
2117 {
2118  return Property::setProperty(mCodecContext, valuesToSet, valuesNotFound);
2119 }
2120 
2121 
2122 int32_t
2123 StreamCoder::setProperty(const char* aName, const char *aValue)
2124 {
2125  return Property::setProperty(mCodecContext, aName, aValue);
2126 }
2127 
2128 int32_t
2129 StreamCoder::setProperty(const char* aName, double aValue)
2130 {
2131  return Property::setProperty(mCodecContext, aName, aValue);
2132 }
2133 
2134 int32_t
2135 StreamCoder::setProperty(const char* aName, int64_t aValue)
2136 {
2137  return Property::setProperty(mCodecContext, aName, aValue);
2138 }
2139 
2140 int32_t
2141 StreamCoder::setProperty(const char* aName, bool aValue)
2142 {
2143  return Property::setProperty(mCodecContext, aName, aValue);
2144 }
2145 
2146 int32_t
2147 StreamCoder::setProperty(const char* aName, IRational *aValue)
2148 {
2149  return Property::setProperty(mCodecContext, aName, aValue);
2150 }
2151 
2152 char*
2153 StreamCoder::getPropertyAsString(const char *aName)
2154 {
2155  return Property::getPropertyAsString(mCodecContext, aName);
2156 }
2157 
2158 double
2159 StreamCoder::getPropertyAsDouble(const char *aName)
2160 {
2161  return Property::getPropertyAsDouble(mCodecContext, aName);
2162 }
2163 
2164 int64_t
2165 StreamCoder::getPropertyAsLong(const char *aName)
2166 {
2167  return Property::getPropertyAsLong(mCodecContext, aName);
2168 }
2169 
2170 IRational*
2171 StreamCoder::getPropertyAsRational(const char *aName)
2172 {
2173  return Property::getPropertyAsRational(mCodecContext, aName);
2174 }
2175 
2176 bool
2177 StreamCoder::getPropertyAsBoolean(const char *aName)
2178 {
2179  return Property::getPropertyAsBoolean(mCodecContext, aName);
2180 }
2181 
2182 bool
2183 StreamCoder::isOpen()
2184 {
2185  return mOpened;
2186 }
2187 
2188 int32_t
2189 StreamCoder::getDefaultAudioFrameSize()
2190 {
2191  return mDefaultAudioFrameSize;
2192 }
2193 
2194 void
2195 StreamCoder::setDefaultAudioFrameSize(int32_t aNewSize)
2196 {
2197  if (aNewSize > 0)
2198  mDefaultAudioFrameSize = aNewSize;
2199 }
2200 
2201 int32_t
2202 StreamCoder::setStream(Stream* stream, bool assumeOnlyStream)
2203 {
2204  int32_t retval = -1;
2205  if (assumeOnlyStream)
2206  mStream = stream;
2207  AVStream *avStream = stream ? stream->getAVStream() : 0;
2208  if (avStream)
2209  {
2210  // This handles the case where FFMPEG actually alloced a stream
2211  // codeccontext and thinks it'll free it later when the input
2212  // file closes. in this case, we free the old value because
2213  // we're about to overwrite it.
2214  if (avStream->codec) {
2215  resetOptions(avStream->codec);
2216  av_freep(&avStream->codec->extradata);
2217  av_freep(&avStream->codec->subtitle_header);
2218  avcodec_free_context(&avStream->codec);
2219  }
2220  avStream->codec = mCodecContext;
2221  }
2222  retval = 0;
2223  return retval;
2224 }
2225 
2226 int64_t
2227 StreamCoder::getNumDroppedFrames()
2228 {
2229  return mNumDroppedFrames;
2230 }
2231 
2232 void
2233 StreamCoder::setAutomaticallyStampPacketsForStream(bool value)
2234 {
2235  // VS_LOG_DEBUG("setAutomaticallyStampPacketsForStream: %d", value);
2236  mAutomaticallyStampPacketsForStream = value;
2237 }
2238 
2239 bool
2240 StreamCoder::getAutomaticallyStampPacketsForStream()
2241 {
2242  return mAutomaticallyStampPacketsForStream;
2243 }
2244 
2245 int32_t
2246 StreamCoder::setExtraData(com::avpkit::ferry::IBuffer* src, int32_t offset,
2247  int32_t numBytes, bool allocNew)
2248 {
2249  if (!mCodecContext || !src)
2250  return -1;
2251 
2252  void* bytes = src->getBytes(offset, numBytes);
2253  if (!bytes)
2254  return -1;
2255 
2256  if (mCodecContext->extradata_size < numBytes || !mCodecContext->extradata)
2257  {
2258  if (allocNew)
2259  {
2260  av_free(mCodecContext->extradata);
2261  mCodecContext->extradata_size = 0;
2262  mCodecContext->extradata = (uint8_t*) av_malloc(numBytes
2263  + AV_INPUT_BUFFER_MIN_SIZE);
2264  if (!mCodecContext->extradata)
2265  {
2266  return -1;
2267  }
2268  mCodecContext->extradata_size = numBytes;
2269  }
2270  else
2271  return -1;
2272  }
2273  memcpy(mCodecContext->extradata, bytes, numBytes);
2274 
2275  if (mStream) {
2276  avcodec_parameters_from_context(mStream->getAVStream()->codecpar, mCodecContext);
2277  }
2278  return numBytes;
2279 }
2280 int32_t
2281 StreamCoder::getExtraData(com::avpkit::ferry::IBuffer *dest, int32_t offset,
2282  int32_t maxBytesToCopy)
2283 {
2284  if (!mCodecContext || !mCodecContext->extradata
2285  || mCodecContext->extradata_size <= 0 || !dest || offset < 0
2286  || maxBytesToCopy < 0 || dest->getSize() < offset + maxBytesToCopy)
2287  return 0;
2288 
2289  int32_t bytesToCopy = FFMIN(maxBytesToCopy, mCodecContext->extradata_size);
2290  if (bytesToCopy <= 0)
2291  return 0;
2292  void* bytes = dest->getBytes(offset, bytesToCopy);
2293  if (!bytes)
2294  return 0;
2295  memcpy(bytes, mCodecContext->extradata, bytesToCopy);
2296  return bytesToCopy;
2297 }
2298 
2299 int32_t
2300 StreamCoder::getExtraDataSize()
2301 {
2302  if (mCodecContext)
2303  return mCodecContext->extradata_size;
2304  return 0;
2305 }
2306 
2308 StreamCoder :: getStandardsCompliance()
2309 {
2310  if (mCodecContext)
2311  return (CodecStandardsCompliance) mCodecContext->strict_std_compliance;
2312  return (CodecStandardsCompliance)0;
2313 }
2314 
2315 int32_t
2316 StreamCoder :: setStandardsCompliance(CodecStandardsCompliance compliance)
2317 {
2318  if (!mCodecContext)
2319  return -1;
2320  mCodecContext->strict_std_compliance = compliance;
2321  return 0;
2322 }
2323 
2324 int32_t
2325 StreamCoder::setHardwareDecoding(const IPixelFormat::Type type, void* surface)
2326 {
2327  if (!(av_pix_fmt_desc_get((AVPixelFormat)type)->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
2328  VS_LOG_WARN("Requested type is not hardware accelerated, default decoder will be used instead %d %d", av_pix_fmt_desc_get((AVPixelFormat)type)->flags, AV_PIX_FMT_FLAG_HWACCEL);
2329  return 0;
2330  }
2331 
2332  if (mCodecContext && mStream) {
2333  AVBufferRef* device_ctx = NULL;
2334  Codec* codec = Codec::findDecodingCodec(mCodec->getID(), type);
2335  if (!codec) {
2336  VS_LOG_WARN("No hardware decoder found for requested type, looking for hwaccel");
2337  for (int i = 0;; i++) {
2338  const AVCodecHWConfig *config = avcodec_get_hw_config(mCodec->getAVCodec(), i);
2339  if (!config) {
2340  VS_LOG_WARN("Decoder %s does not support any device type",
2341  mCodec->getAVCodec()->name);
2342  break;
2343  }
2344  if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
2345  config->pix_fmt == (AVPixelFormat)type) {
2346  if (av_hwdevice_ctx_create(&device_ctx, config->device_type, NULL, NULL, 0) < 0) {
2347  VS_LOG_WARN("Unable to create device for type %s", av_hwdevice_get_type_name(config->device_type));
2348  return -1;
2349  }
2350  mCodecContext->hw_device_ctx = av_buffer_ref(device_ctx);
2351  return 0;
2352  }
2353  }
2354  if (!device_ctx) {
2355  VS_LOG_WARN("No hardware decoder found for requested type, default decoder will be used instead");
2356  return 0;
2357  }
2358  }
2359 
2360  avcodec_free_context(&mCodecContext);
2361  mCodecContext = avcodec_alloc_context3(codec->getAVCodec());
2362  if (mCodecContext){
2363  if (avcodec_parameters_to_context(mCodecContext, mStream->getAVStream()->codecpar) < 0)
2364  throw std::runtime_error("could not initialize codec");
2365  }
2366 
2367  readyAVContexts(mDirection,
2368  this,
2369  mStream,
2370  codec,
2371  mCodecContext,
2372  NULL);
2373 
2374  if (type == IPixelFormat::MEDIACODEC) {
2375  #ifdef __ANDROID__
2376  if (!mCodecContext->hwaccel_context && surface){
2377  jobject jSurface = static_cast<jobject>(surface);
2378  if (jSurface){
2379  mediacodec_alloc_context(mCodecContext, JNIHelper::sGetEnv(), jSurface);
2380  }
2381  }
2382  #elif __APPLE__
2383  #else
2384  VS_LOG_WARN("Try to use MediaCodec Android hardware type on non Android platform");
2385  #endif
2386  } else {
2387  VS_LOG_WARN("Hardware context not yet supported %s", mCodecContext->hwaccel->name);
2388  }
2389  } else {
2390  VS_LOG_WARN("try to set HW decoding on uninitialized AVContext or AVStream");
2391  }
2392  return 0;
2393 }
2394 
2395 void*
2396 StreamCoder::getHardwareSurface()
2397 {
2398  #ifdef __ANDROID__
2399  return mediacodec_create_input_surface(mCodecContext, JNIHelper::sGetEnv());
2400  #else
2401  VS_LOG_WARN("Hardware surface not yet supported");
2402  #endif
2403 }
2404 
2405 }
2406 }
2407 }
virtual int32_t getSampleRate()
Find the sample rate of the samples in this audio buffer.
virtual int64_t getTimeStamp()
Get the time stamp of this object in getTimeBase() units.
Definition: AudioSamples.h:37
virtual int32_t getChannels()
Return the number of channels of the samples in this buffer.
virtual int32_t ensureCapacity(int32_t capacityInBytes)
Called by decoder before decoding to ensure sufficient space.
virtual void setComplete(bool complete, int32_t numSamples, int32_t sampleRate, int32_t channels, Format sampleFmt, int64_t pts)
Call this if you modify the samples and are now done.
virtual int64_t getPts()
What is the Presentation Time Stamp of this set of audio samples.
virtual int32_t getMaxBufferSize()
virtual int32_t getNumSamples()
Get the number of samples in this video.
virtual bool isComplete()
Returns whether or not we think this buffer has been filled with data.
A set of raw (decoded) samples, plus a timestamp for when to play those samples relative to other ite...
Definition: IAudioSamples.h:38
Format
The format we use to represent audio.
Definition: IAudioSamples.h:46
A "key" to an IStreamCoder that tells it how to encode or decode data.
Definition: ICodec.h:53
ID
These are the codecs this library currently supports.
Definition: ICodec.h:61
Type
The different types of Codecs that can exist in the system.
Definition: ICodec.h:582
Get MetaData about a IContainer or IStream.
Definition: IMetaData.h:51
Represents an encoded piece of data that can be placed in an IContainer for a given IStream of data.
Definition: IPacket.h:50
Represents settable properties that effect how AVPKit objects operate.
Definition: IProperty.h:37
This class wraps represents a Rational number for the AVPKit.
Definition: IRational.h:43
virtual int64_t rescale(int64_t origValue, IRational *origBase)=0
Takes a value scaled in increments of origBase and gives the equivalent value scaled in terms of this...
virtual int32_t getDenominator()=0
Get the denominator for this rational.
virtual int32_t getNumerator()=0
Get the numerator for this rational.
CodecStandardsCompliance
An enumeration of how strictly Codecs may follow the spec.
Definition: IStreamCoder.h:959
Flags
AVPKIT Flags that can be passed to the setFlag(Flags, bool) method.
Definition: IStreamCoder.h:60
Direction
The Direction in which this StreamCoder will work.
Definition: IStreamCoder.h:52
Represents a stream of similar data (eg video) in a IContainer.
Definition: IStream.h:50
Represents one raw (undecoded) picture in a video stream, plus a timestamp for when to display that v...
Definition: IVideoPicture.h:40
int32_t copy(IMetaData *copy)
Destroys the current data, and copies all data from copy.
Definition: MetaData.cpp:164
AVDictionary * getDictionary()
Returns the AVDictionary for passing to FFmpeg calls.
Definition: MetaData.h:76
virtual int32_t allocateNewPayload(int32_t payloadSize)
Discard the current payload and allocate a new payload.
Definition: Packet.cpp:309
virtual int64_t getPts()
Get the Presentation Time Stamp (PTS) for this packet.
Definition: Packet.cpp:63
virtual void setKeyPacket(bool keyPacket)
Set if this is a key packet.
Definition: Packet.cpp:113
virtual void setDuration(int64_t duration)
Set the duration.
Definition: Packet.cpp:155
virtual com::avpkit::ferry::IBuffer * getData()
Get any underlying raw data available for this object.
Definition: Packet.cpp:173
virtual void setStreamIndex(int32_t streamIndex)
Set the stream index for this packet.
Definition: Packet.cpp:143
virtual void reset()
Clear out any data in this packet, but leaves the buffer available for reuse.
Definition: Packet.cpp:211
virtual int32_t getSize()
Get the size in bytes of the payload currently in this packet.
Definition: Packet.cpp:87
virtual void setPts(int64_t pts)
Set a new Presentation Time Stamp (PTS) for this packet.
Definition: Packet.cpp:69
virtual void setDts(int64_t dts)
Set a new Decompression Time Stamp (DTS) for this packet.
Definition: Packet.cpp:81
virtual void setComplete(bool complete, int32_t size)
Set if this packet is complete, and what the total size of the data should be assumed to be.
Definition: Packet.cpp:132
virtual void setTimeBase(IRational *aBase)
Set the time base that time stamps of this object are represented in.
Definition: Packet.h:50
virtual void setComplete(bool aIsComplete, IPixelFormat::Type format, int width, int height, int64_t pts)
After modifying the raw data in this buffer, call this function to let the object know it is now comp...
virtual int64_t getPts()
What is the Presentation Time Stamp (in Microseconds) of this picture.
virtual IPixelFormat::Type getPixelType()
Returns the pixel format of the picture.
Definition: VideoPicture.h:50
virtual int32_t getSize()
Total size in bytes of the decoded picture.
void copyAVFrame(AVFrame *frame, IPixelFormat::Type pixel, int32_t width, int32_t height)
Called by the StreamCoder once it's done decoding.
void fillAVFrame(AVFrame *frame)
Called by the StreamCoder before it encodes a picture.
virtual int getWidth()
What is the width of the picture.
Definition: VideoPicture.h:48
virtual int getHeight()
What is the height of the picture.
Definition: VideoPicture.h:49
Allows Java code to get data from a native buffers, and optionally modify native memory directly.
Definition: IBuffer.h:54
virtual void * getBytes(int32_t offset, int32_t length)=0
Returns up to length bytes, starting at offset in the underlying buffer we're managing.
This class is only useful from C++.
Definition: RefPointer.h:47
T * value()
Return the managed pointer without calling RefCounted::acquire() on it.
Definition: RefPointer.h:226
void reset(T *ptr=0, bool acquire=false)
Reset the managed pointer, calling RefCounted::release() on the previously managed pointer first.
Definition: RefPointer.h:237
This library contains routines used by AVPKit libraries for "ferry"ing Java objects to and from nativ...
WARNING: Do not use logging in this class, and do not set any static file variables to values other t...