FFMPEG ffmpeg + cocos2d video test

ShoppingChen 2020-06-25

//核心

{

void AVdio::update(float delta)
{
	auto video = (Sprite*)(this->getChildByName("video"));
	if (video != nullptr)
	{
		double      tims = fl->_pts * fl->_timeBase * 1000;
		double      elsped = _timestamp.getElapsedTimeInMilliSec();
		double      sleeps = (tims - elsped);

		s = sleeps + elsped;

		if (elsped - s > 0.0001)
		{
			is = ffReader.readFrame(*fl);
			if (is)
			{
				texture->initWithData((const unsigned char*)fl->_data, fl->_dataSize, Texture2D::PixelFormat::RGB888,
					fl->_width, fl->_height,
					Size(fl->_width, fl->_height));

				video->initWithTexture(texture);
				video->setContentSize(Size(displayex.width - 10, displayex.height - 50));
			}
			else
			{
				video->removeFromParent();
			}
		}
	}

}

}

.h

{

#ifndef __AVDIO_H__
#define __AVDIO_H__

#include "cocos2d.h"
using namespace cocos2d;
#include <string.h>
#include <iostream>
#include "cocos/ui/CocosGUI.h"
#include "socket/Private/ThreadPool.h"
#include "Tools/Tools.h"
#include "xml/XML.h"
#include "iconv/UTF8.h"
#ifdef _WIN32
#include "ATBAudioEngine/ATBAudioEngine.h"
#endif
using namespace std;
using namespace ui;


class AVdio :public LayerColor, EditBoxDelegate
{
	Tools m_Tools;
public:

	static cocos2d::LayerColor* createAVdio();

	~AVdio();

	virtual bool init();

	CREATE_FUNC(AVdio);



	void OnCallback(cocos2d::Ref* pSender);
	virtual bool onTouchBegan(Touch *touch, Event *unused_event) override;
	virtual void update(float delta);

	virtual void editBoxEditingDidBegin(EditBox* editBox)override;
	CC_DEPRECATED_ATTRIBUTE virtual void editBoxEditingDidEnd(EditBox* editBox)override;
	virtual void editBoxTextChanged(EditBox* editBox, const std::string& text)override;
	virtual void editBoxReturn(EditBox* editBox)override;
	virtual void editBoxEditingDidEndWithAction(EditBox* editBox, EditBoxDelegate::EditBoxEndAction action)override;
private:
	void initVideoStream(string filename);
	void initInput();
};

extern "C"
{
#include <libavutil/imgutils.h>
#include <libavutil/parseutils.h>
#include <libswscale/swscale.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
#include <libavdevice/avdevice.h>
}

struct  FrameInfor
{
	void*   _data;
	int     _dataSize;
	int     _width;
	int     _height;
	int64_t _pts;
	double  _timeBase;

};
class   FFVideoReader
{
public:
	AVFormatContext*_formatCtx;
	int             _videoIndex;
	AVCodecContext* _codecCtx;
	AVCodec*        _codec;
	AVFrame*        _frame;
	AVFrame*        _frameRGB;
	SwsContext*     _convertCtx;
public:
	int             _screenW;
	int             _screenH;

	int             _imageSize;
public:
	FFVideoReader()
	{
		_formatCtx = 0;
		_videoIndex = -1;
		_codecCtx = 0;
		_codec = 0;
		_frame = 0;
		_frameRGB = 0;
		_convertCtx = 0;
		_screenW = 0;
		_screenH = 0;

	}

	~FFVideoReader()
	{
		sws_freeContext(_convertCtx);
		av_free(_frameRGB);
		av_free(_frame);
		avcodec_close(_codecCtx);
		avformat_close_input(&_formatCtx);
	}

	void    setup()
	{
		av_register_all();
		_formatCtx = avformat_alloc_context();
	}
	int     load(const char* filepath = "11.flv")
	{
		int     ret = 0;

		//! 打开文件
		if (avformat_open_input(&_formatCtx, filepath, NULL, NULL) != 0)
		{
			return -1;
		}
		//! 检测文件中是否存在数据流
		if (avformat_find_stream_info(_formatCtx, NULL) < 0)
		{
			printf("检测文件中是否存在数据流");
			return -1;
		}
		//! 获取视频流索引
		_videoIndex = -1;
		for (int i = 0; i < _formatCtx->nb_streams; i++)
		{
			if (_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
			{
				_videoIndex = i;
				break;
			}
		}
		/**
		*   没有视频流,则返回
		*/
		if (_videoIndex == -1)
		{
			return -1;
		}
		_codecCtx = _formatCtx->streams[_videoIndex]->codec;

		double dur = _formatCtx->duration / double(AV_TIME_BASE);
		_codec = avcodec_find_decoder(_codecCtx->codec_id);
		if (_codec == NULL)
		{
			printf("find decoder faild !!\n");
			return -1;
		}
		/**
		*   打开解码器
		*/
		if (avcodec_open2(_codecCtx, _codec, NULL) < 0)
		{
			return -1;
		}
		_frame = av_frame_alloc();
		_frameRGB = av_frame_alloc();

		_screenW = _codecCtx->width;
		_screenH = _codecCtx->height;

		_convertCtx = sws_getContext(
			_codecCtx->width
			, _codecCtx->height
			, _codecCtx->pix_fmt
			, _codecCtx->width
			, _codecCtx->height
			, AV_PIX_FMT_RGB24
			, SWS_BICUBIC
			, NULL
			, NULL
			, NULL
		);

		int     numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, _codecCtx->width, _codecCtx->height);
		uint8_t*buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
		avpicture_fill((AVPicture *)_frameRGB, buffer, AV_PIX_FMT_RGB24, _codecCtx->width, _codecCtx->height);
		_imageSize = numBytes;
		return  0;
	}

	bool    readFrame(FrameInfor& infor)
	{
		AVPacket packet;
		av_init_packet(&packet);
		for (;;)
		{
			if (av_read_frame(_formatCtx, &packet))
			{
				av_free_packet(&packet);
				return false;
			}
			if (packet.stream_index != _videoIndex)
			{
				continue;
			}
			int frame_finished = 0;

			int res = avcodec_decode_video2(_codecCtx, _frame, &frame_finished, &packet);

			if (frame_finished)
			{
				AVStream*   streams = _formatCtx->streams[_videoIndex];
				double      tmbase = av_q2d(streams->time_base);
				int64_t     pts = _frame->pts;

				char        buf[128];
				sprintf(buf, "pts = %I64d     dts =  %I64d\n", packet.pts, packet.dts);
				int res = sws_scale(
					_convertCtx
					, (const uint8_t* const*)_frame->data
					, _frame->linesize
					, 0
					, _codecCtx->height
					, _frameRGB->data
					, _frameRGB->linesize
				);
				av_packet_unref(&packet);

				infor._data = _frameRGB->data[0];
				infor._dataSize = _imageSize;
				infor._width = _screenW;
				infor._height = _screenH;
				infor._pts = _frame->pts;
				infor._timeBase = av_q2d(streams->time_base);

				return  true;
			}
		}
		return  false;
	}
	void*   readFrame()
	{
		AVPacket packet;
		av_init_packet(&packet);
		for (;;)
		{
			if (av_read_frame(_formatCtx, &packet))
			{
				av_free_packet(&packet);
				return 0;
			}
			if (packet.stream_index != _videoIndex)
			{
				continue;
			}
			int frame_finished = 0;

			int res = avcodec_decode_video2(_codecCtx, _frame, &frame_finished, &packet);

			if (frame_finished)
			{
				AVStream*   streams = _formatCtx->streams[_videoIndex];
				double      tmbase = av_q2d(streams->time_base);
				int64_t     pts = _frame->pts;

				char        buf[128];
				sprintf(buf, "pts = %I64d     dts =  %I64d\n", packet.pts, packet.dts);
				int res = sws_scale(
					_convertCtx
					, (const uint8_t* const*)_frame->data
					, _frame->linesize
					, 0
					, _codecCtx->height
					, _frameRGB->data
					, _frameRGB->linesize
				);
				av_packet_unref(&packet);

				return  _frameRGB->data[0];
			}
		}
		return  0;
	}
};



#include <windows.h>

class Timestamp
{
public:
	Timestamp()
	{
		QueryPerformanceFrequency(&_frequency);
		QueryPerformanceCounter(&_startCount);
	}
	~Timestamp()
	{}

	void    update()
	{
		QueryPerformanceCounter(&_startCount);
	}
	/**
	*   获取当前秒
	*/
	double getElapsedSecond()
	{
		return  getElapsedTimeInMicroSec() * 0.000001;
	}
	/**
	*   获取毫秒
	*/
	double getElapsedTimeInMilliSec()
	{
		return this->getElapsedTimeInMicroSec() * 0.001;
	}
	/**
	*   获取微妙
	*/
	double getElapsedTimeInMicroSec()
	{
		LARGE_INTEGER endCount;
		QueryPerformanceCounter(&endCount);

		double  startTimeInMicroSec = _startCount.QuadPart * (1000000.0 / _frequency.QuadPart);
		double  endTimeInMicroSec = endCount.QuadPart * (1000000.0 / _frequency.QuadPart);

		return  endTimeInMicroSec - startTimeInMicroSec;
	}
protected:
	LARGE_INTEGER   _frequency;
	LARGE_INTEGER   _startCount;
};





#endif

}

.cpp

{

#include "AVdio.h"

#ifndef DISPLAY
#define DISPLAY Director::getInstance()->getVisibleSize()
#endif
#ifndef displayex
#define displayex Director::getInstance()->getVisibleSize()
#endif


FFVideoReader   ffReader;
FrameInfor *fl = new (std::nothrow) FrameInfor;
auto texture = new (std::nothrow) Texture2D();
bool is = false;
Timestamp       _timestamp;
double s = 0;


cocos2d::LayerColor* AVdio::createAVdio()
{
	auto LC = AVdio::create();
	if (LC)
	{
		return LC;
	}
	else
	{
		return nullptr;
	}
}

AVdio::~AVdio()
{

}

void AVdio::update(float delta)
{
	auto video = (Sprite*)(this->getChildByName("video"));
	if (video != nullptr)
	{
		double      tims = fl->_pts * fl->_timeBase * 1000;
		double      elsped = _timestamp.getElapsedTimeInMilliSec();
		double      sleeps = (tims - elsped);

		s = sleeps + elsped;

		if (elsped - s > 0.0001)
		{
			is = ffReader.readFrame(*fl);
			if (is)
			{
				texture->initWithData((const unsigned char*)fl->_data, fl->_dataSize, Texture2D::PixelFormat::RGB888,
					fl->_width, fl->_height,
					Size(fl->_width, fl->_height));

				video->initWithTexture(texture);
				video->setContentSize(Size(displayex.width - 10, displayex.height - 50));
			}
			else
			{
				video->removeFromParent();
			}
		}
	}

}

bool AVdio::init()
{
	if (!LayerColor::init())
	{
		return false;
	}

	auto display = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();

	this->setTouchEnabled(true);
	auto ELTOBO = EventListenerTouchOneByOne::create();
	ELTOBO->setSwallowTouches(true);
	ELTOBO->onTouchBegan = std::move(std::bind(&AVdio::onTouchBegan, this, std::placeholders::_1, std::placeholders::_2));
	this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(ELTOBO, this);




	auto background = cocos2d::LayerColor::create(cocos2d::Color4B(0, 0, 0, 255));
	this->addChild(background);

	//close button
	string file("res/Button.png");
	auto btn = cocos2d::ui::Button::create(file, file, file);
	btn->setColor(Color3B(24, 48, 64));
	btn->setPressedActionEnabled(true);
	btn->setScale9Enabled(true);
	btn->setContentSize(Size(100, 50));
	btn->setPosition(Vec2(displayex.width - btn->getContentSize().width / 2,
		displayex.height - btn->getContentSize().height / 2));
	btn->setTitleColor(Color3B::RED);
	btn->setTitleFontSize(50);
	btn->setName("X");
	btn->setTitleText("X");
	btn->addClickEventListener(std::bind(&AVdio::OnCallback, this, std::placeholders::_1));
	this->addChild(btn);


	//this->initVideoStream();

	this->initInput();
}

void AVdio::initInput()
{
	auto edit = ui::EditBox::create(Size(800, 50), "res/input.png");
	edit->setPosition(Vec2(0, displayex.height - edit->getContentSize().height / 2));
	edit->setAnchorPoint(Vec2(0.0f, 0.5f));
	edit->setName("videoPath");
	edit->setFontColor(Color4B::YELLOW);
	edit->setDelegate(this);
	this->addChild(edit);

	string file("res/Button.png");
	auto btn = cocos2d::ui::Button::create(file, file, file);
	btn->setColor(Color3B(24, 48, 64));
	btn->setPressedActionEnabled(true);
	btn->setScale9Enabled(true);
	btn->setContentSize(Size(150, 50));
	btn->setPosition(Vec2(displayex.width - (displayex.width - edit->getContentSize().width) + btn->getContentSize().width / 2,
		edit->getPosition().y));
	btn->setTitleColor(Color3B::RED);
	btn->setTitleFontSize(50);
	btn->setName("PLAY");
	btn->setTitleText("PLAY");
	btn->addClickEventListener(std::bind(&AVdio::OnCallback, this, std::placeholders::_1));
	this->addChild(btn);
}

void AVdio::initVideoStream(string filename)
{
	this->unscheduleUpdate();

	_timestamp.update();
	
	

	ATBAE::GetInstance()->PauseAllMusicAndEffects();
	auto video = (Sprite*)(this->getChildByName("video"));
	if (video != nullptr)
	{
		video->removeFromParent();
	}

	s = 0;

	auto display = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();

	auto ret = avdevice_version();
	std::cout << ret << std::endl;

	ffReader.~FFVideoReader();
	ffReader.setup();
	ffReader.load(filename.c_str());

	ATBAE::GetInstance()->LoadMusicsAndPlay(filename.c_str());


	is = ffReader.readFrame(*fl);

	texture->initWithData((const unsigned char*)fl->_data, fl->_dataSize, Texture2D::PixelFormat::RGB888,
		fl->_width - 1, fl->_height - 1,
		Size(500, 500));

	auto s = Sprite::create("06a03.jpg");
	s->initWithTexture(texture);
	s->setName("video");
	s->setPosition(Vec2(display.width / 2, display.height / 2 - 25));
	this->addChild(s);

	this->scheduleUpdate();
}


void AVdio::OnCallback(cocos2d::Ref* pSender)
{
	string name = ((Node*)(pSender))->getName();
	if (name == "X")
	{
		auto action = Sequence::create(MoveTo::create(0.2f, Vec3(-(displayex.width), 0, 0)),
			DelayTime::create(0.1f),
			CallFunc::create([=]()
		{
			this->removeFromParent();
			ATBAE::GetInstance()->PauseAllMusicAndEffects();
		}), nullptr);
		this->runAction(action);
	}
	else if (name == "PLAY")
	{
		auto edit = (ui::EditBox*)this->getChildByName("videoPath");
		string path = edit->getText();
		if (path.length() > 0)
		{
			this->initVideoStream(path);
		}
		
	}
}
bool AVdio::onTouchBegan(Touch *touch, Event *unused_event)
{
	return true;
}


void AVdio::editBoxEditingDidBegin(EditBox* editBox)
{

}
void AVdio::editBoxEditingDidEnd(EditBox* editBox)
{

}
void AVdio::editBoxTextChanged(EditBox* editBox, const std::string& text)
{

}
void AVdio::editBoxReturn(EditBox* editBox)
{

}
void AVdio::editBoxEditingDidEndWithAction(EditBox* editBox, EditBoxDelegate::EditBoxEndAction action)
{

}

}

相关推荐

cherayliu / 0评论 2020-06-13

83096129 / 0评论 2020-01-05