|
1 | 1 | #include "VideoProperties.hpp"
|
2 | 2 |
|
| 3 | +#include <AvTranscoder/util.hpp> |
| 4 | +#include <AvTranscoder/decoder/VideoDecoder.hpp> |
| 5 | +#include <AvTranscoder/data/decoded/VideoFrame.hpp> |
3 | 6 | #include <AvTranscoder/properties/util.hpp>
|
4 | 7 | #include <AvTranscoder/properties/FileProperties.hpp>
|
5 | 8 | #include <AvTranscoder/progress/NoDisplayProgress.hpp>
|
6 |
| -#include <AvTranscoder/data/decoded/VideoFrame.hpp> |
7 | 9 |
|
8 | 10 | extern "C" {
|
9 | 11 | #include <libavutil/avutil.h>
|
@@ -328,78 +330,20 @@ size_t VideoProperties::getBitRate() const
|
328 | 330 | if(_codecContext->bit_rate || _codecContext->rc_max_rate)
|
329 | 331 | return _codecContext->bit_rate;
|
330 | 332 |
|
331 |
| - LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown.") |
332 |
| - LOG_INFO("Compute the video bitrate by decoding the first GOP.") |
333 |
| - |
334 |
| - if(!_codecContext->width || !_codecContext->height) |
335 |
| - throw std::runtime_error("cannot compute bit rate: invalid frame size"); |
336 |
| - |
337 |
| - if(!_formatContext || !_codec) |
338 |
| - throw std::runtime_error("cannot compute bit rate: unknown format or codec"); |
339 |
| - if(!_codecContext->width || !_codecContext->height) |
340 |
| - throw std::runtime_error("cannot compute bit rate: invalid frame size"); |
341 |
| - |
342 |
| - // discard no frame type when decode |
343 |
| - _codecContext->skip_frame = AVDISCARD_NONE; |
344 |
| - |
345 |
| - AVPacket pkt; |
346 |
| - av_init_packet(&pkt); |
347 |
| - |
348 |
| - avcodec_open2(_codecContext, _codec, NULL); |
349 |
| - |
350 |
| - VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelProperties().getPixelFormatName()), false); |
351 |
| - AVFrame& avFrame = frame.getAVFrame(); |
352 |
| - |
353 |
| - int gotFrame = 0; |
354 |
| - size_t nbDecodedFrames = 0; |
355 |
| - int gopFramesSize = 0; |
356 |
| - int positionOfFirstKeyFrame = -1; |
357 |
| - int positionOfLastKeyFrame = -1; |
358 |
| - |
359 |
| - while(!av_read_frame(const_cast<AVFormatContext*>(_formatContext), &pkt)) |
| 333 | + if(_levelAnalysis == eAnalyseLevelHeader) |
360 | 334 | {
|
361 |
| - if(pkt.stream_index == (int)_streamIndex) |
362 |
| - { |
363 |
| - avcodec_decode_video2(_codecContext, &avFrame, &gotFrame, &pkt); |
364 |
| - if(gotFrame) |
365 |
| - { |
366 |
| - // check distance between key frames |
367 |
| - if(avFrame.pict_type == AV_PICTURE_TYPE_I) |
368 |
| - { |
369 |
| - if(positionOfFirstKeyFrame == -1) |
370 |
| - positionOfFirstKeyFrame = nbDecodedFrames; |
371 |
| - else |
372 |
| - positionOfLastKeyFrame = nbDecodedFrames; |
373 |
| - } |
374 |
| - ++nbDecodedFrames; |
375 |
| - |
376 |
| - // added size of all frames of the same gop |
377 |
| - if(positionOfLastKeyFrame == -1) |
378 |
| - { |
379 |
| -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 7, 100) |
380 |
| - gopFramesSize += av_frame_get_pkt_size(&avFrame); |
381 |
| -#else |
382 |
| - gopFramesSize += pkt.size; |
383 |
| -#endif |
384 |
| - } |
385 |
| - } |
386 |
| - } |
387 |
| - av_free_packet(&pkt); |
388 |
| - if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) |
389 |
| - break; |
| 335 | + LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown. " |
| 336 | + "Need a deeper analysis: see eAnalyseLevelFirstGop.") |
| 337 | + return 0; |
390 | 338 | }
|
391 |
| - // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself) |
392 |
| - avcodec_close(_codecContext); |
393 |
| - // Returns at the beginning of the stream |
394 |
| - const_cast<FormatContext*>(&_fileProperties->getFormatContext())->seek(0, AVSEEK_FLAG_BYTE); |
395 | 339 |
|
396 |
| - const size_t gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame; |
397 |
| - if(gopSize > 0) |
| 340 | + LOG_INFO("Estimate the video bitrate from the first GOP.") |
| 341 | + size_t gopFramesSize = 0; |
| 342 | + for(size_t picture = 0; picture < _gopStructure.size(); ++picture) |
398 | 343 | {
|
399 |
| - const float fps = av_q2d(_formatContext->streams[_streamIndex]->avg_frame_rate); |
400 |
| - return (gopFramesSize / gopSize) * 8 * fps; |
| 344 | + gopFramesSize += _gopStructure.at(picture).second; |
401 | 345 | }
|
402 |
| - return 0; |
| 346 | + return (gopFramesSize / getGopSize()) * 8 * getFps(); |
403 | 347 | }
|
404 | 348 |
|
405 | 349 | size_t VideoProperties::getMaxBitRate() const
|
@@ -556,69 +500,59 @@ std::vector<std::pair<char, int> > VideoProperties::getGopStructure() const
|
556 | 500 |
|
557 | 501 | void VideoProperties::analyseGopStructure(IProgress& progress)
|
558 | 502 | {
|
559 |
| - if(_formatContext && _codecContext && _codec) |
| 503 | + if(! _formatContext || ! _codecContext || ! _codec) |
| 504 | + return; |
| 505 | + if(! _codecContext->width || ! _codecContext->height) |
| 506 | + return; |
| 507 | + |
| 508 | + InputFile& file = const_cast<InputFile&>(_fileProperties->getInputFile()); |
| 509 | + // Get the stream |
| 510 | + IInputStream& stream = file.getStream(_streamIndex); |
| 511 | + stream.activate(); |
| 512 | + // Create a decoder |
| 513 | + VideoDecoder decoder(static_cast<InputStream&>(stream)); |
| 514 | + |
| 515 | + size_t count = 0; |
| 516 | + int positionOfFirstKeyFrame = -1; |
| 517 | + int positionOfLastKeyFrame = -1; |
| 518 | + VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelFormatName(getPixelProperties().getAVPixelFormat())), false); |
| 519 | + while(decoder.decodeNextFrame(frame)) |
560 | 520 | {
|
561 |
| - if(_codecContext->width && _codecContext->height) |
| 521 | + AVFrame& avFrame = frame.getAVFrame(); |
| 522 | + |
| 523 | + _gopStructure.push_back( |
| 524 | + std::make_pair(av_get_picture_type_char(avFrame.pict_type), av_frame_get_pkt_size(&avFrame))); |
| 525 | + _isInterlaced = avFrame.interlaced_frame; |
| 526 | + _isTopFieldFirst = avFrame.top_field_first; |
| 527 | + if(avFrame.pict_type == AV_PICTURE_TYPE_I) |
562 | 528 | {
|
563 |
| - // Discard no frame type when decode |
564 |
| - _codecContext->skip_frame = AVDISCARD_NONE; |
565 |
| - |
566 |
| - AVPacket pkt; |
567 |
| - av_init_packet(&pkt); |
568 |
| - |
569 |
| - // Initialize the AVCodecContext to use the given AVCodec |
570 |
| - avcodec_open2(_codecContext, _codec, NULL); |
571 |
| - |
572 |
| - VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelProperties().getPixelFormatName()), false); |
573 |
| - AVFrame& avFrame = frame.getAVFrame(); |
574 |
| - |
575 |
| - size_t count = 0; |
576 |
| - int gotFrame = 0; |
577 |
| - int positionOfFirstKeyFrame = -1; |
578 |
| - int positionOfLastKeyFrame = -1; |
579 |
| - |
580 |
| - while(!av_read_frame(const_cast<AVFormatContext*>(_formatContext), &pkt)) |
581 |
| - { |
582 |
| - if(pkt.stream_index == (int)_streamIndex) |
583 |
| - { |
584 |
| - avcodec_decode_video2(_codecContext, &avFrame, &gotFrame, &pkt); |
585 |
| - if(gotFrame) |
586 |
| - { |
587 |
| - _gopStructure.push_back( |
588 |
| - std::make_pair(av_get_picture_type_char(avFrame.pict_type), av_frame_get_pkt_size(&avFrame))); |
589 |
| - _isInterlaced = avFrame.interlaced_frame; |
590 |
| - _isTopFieldFirst = avFrame.top_field_first; |
591 |
| - if(avFrame.pict_type == AV_PICTURE_TYPE_I) |
592 |
| - { |
593 |
| - if(positionOfFirstKeyFrame == -1) |
594 |
| - positionOfFirstKeyFrame = count; |
595 |
| - else |
596 |
| - positionOfLastKeyFrame = count; |
597 |
| - } |
598 |
| - |
599 |
| - _gopSize = ++count; |
600 |
| - } |
601 |
| - } |
602 |
| - av_free_packet(&pkt); |
603 |
| - |
604 |
| - // If the first 2 key frames are found |
605 |
| - if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) |
606 |
| - { |
607 |
| - // Set gop size as distance between these 2 key frames |
608 |
| - _gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame; |
609 |
| - // Update gop structure to keep only one gop |
610 |
| - while(_gopStructure.size() > _gopSize) |
611 |
| - _gopStructure.pop_back(); |
612 |
| - break; |
613 |
| - } |
614 |
| - } |
615 |
| - |
616 |
| - // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself) |
617 |
| - avcodec_close(_codecContext); |
618 |
| - |
619 |
| - // Returns at the beginning of the stream |
620 |
| - const_cast<FormatContext*>(&_fileProperties->getFormatContext())->seek(0, AVSEEK_FLAG_BYTE); |
| 529 | + if(positionOfFirstKeyFrame == -1) |
| 530 | + positionOfFirstKeyFrame = count; |
| 531 | + else |
| 532 | + positionOfLastKeyFrame = count; |
621 | 533 | }
|
| 534 | + |
| 535 | + _gopSize = ++count; |
| 536 | + |
| 537 | + // If the first 2 key frames are found |
| 538 | + if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) |
| 539 | + { |
| 540 | + // Set gop size as distance between these 2 key frames |
| 541 | + _gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame; |
| 542 | + // Update gop structure to keep only one gop |
| 543 | + while(_gopStructure.size() > _gopSize) |
| 544 | + _gopStructure.pop_back(); |
| 545 | + break; |
| 546 | + } |
| 547 | + } |
| 548 | + |
| 549 | + // Returns at the beginning of the stream |
| 550 | + file.seekAtFrame(0, AVSEEK_FLAG_BYTE); |
| 551 | + |
| 552 | + // Check GOP size |
| 553 | + if(_gopSize <= 0) |
| 554 | + { |
| 555 | + throw std::runtime_error("Invalid GOP size when decoding the first data."); |
622 | 556 | }
|
623 | 557 | }
|
624 | 558 |
|
|
0 commit comments