2023. 3. 14. 19:26ㆍcocos2dx
소리 재생부분은 일단은 필요없어서 넣지 않았음.
linker에 연결할 부분은
avcodec.lib
avformat.lib
avutil.lib
swscale.lib
ffmpeg 3.4.1 32bit shared library를 갖고 작업함. 여기 올리고 싶은데 압축파일이 커서...
#include "cocos2d.h"
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/avutil.h"
#include "libavutil/imgutils.h"
}
class LayerMovie : public cocos2d::Layer
{
public:
static LayerMovie* create(const std::string fileName);
LayerMovie(const std::string fileName) : v_spr(NULL)
{
v_name = fileName;
// Initalizing these to NULL prevents segfaults!
pFormatCtx = NULL;
pCodecCtxOrig = pCodecCtx = NULL;
pCodec = NULL;
pFrame = pFrameRGB = NULL;
buffer = NULL;
sws_ctx = NULL;
}
~LayerMovie()
{
// Free the RGB image
if (buffer) av_free(buffer);
if (pFrameRGB) av_frame_free(&pFrameRGB);
// Free the YUV frame
if (pFrame) av_frame_free(&pFrame);
// Close the codecs
if (pCodecCtx) avcodec_close(pCodecCtx);
if (pCodecCtxOrig) avcodec_close(pCodecCtxOrig);
// Close the video file
if (pFormatCtx) avformat_close_input(&pFormatCtx);
}
public:
std::string v_name;
cocos2d::Sprite* v_spr;
bool _loop;
//FFmpeg movie datas
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtxOrig, *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame, *pFrameRGB;
AVPacket packet;
struct SwsContext *sws_ctx;
uint8_t *buffer;
int videoStream;
int frameFinished;
int numBytes;
public:
bool init();
void updateFrame(float dt);
bool setLoop(bool v = true);
void setWidth(float width);
void setSize(cocos2d::Size size);
float getWidth();
float getHeight();
};
#include "LayerMovie.h"
// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif
LayerMovie* LayerMovie::create(const std::string fileName)
{
LayerMovie *pRet = new LayerMovie(fileName);
if (pRet && pRet->init())
{
pRet->autorelease();
return pRet;
}
else
{
delete pRet;
pRet = nullptr;
return nullptr;
}
}
bool LayerMovie::init()
{
// Register all formats and codecs
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, v_name.c_str(), NULL, NULL) != 0) return false;
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) return false;
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, v_name.c_str(), 0);
// Find the first video stream
videoStream = -1;
for (int i = 0; i<pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
if (videoStream == -1) return false; // Didn't find a video stream
// set Frame update time(for cocos2d)
double uTime = 1.0 / av_q2d(pFormatCtx->streams[videoStream]->avg_frame_rate);
// Get a pointer to the codec context for the video stream
pCodecCtxOrig = pFormatCtx->streams[videoStream]->codec;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id);
if (pCodec == NULL) {
printf("Unsupported codec!\n");
return false; // Codec not found
}
// Copy context
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
printf("Couldn't copy codec context\n");
return false; // Error copying codec context
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL)<0) return false;
// Allocate video frame
pFrame = av_frame_alloc();
// pCodec -> target 으로 변환하는 규칙 설정이다.
sws_ctx = sws_getContext(pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
AV_PIX_FMT_RGBA,
SWS_BILINEAR,
NULL,
NULL,
NULL
);
//이미지용 프레임, 버퍼크기, 버퍼 할당
//프레임 구조
pFrameRGB = av_frame_alloc();
if (pFrame == NULL || pFrameRGB == NULL) return false;
//버퍼 크기
numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGBA, pCodecCtx->width,
pCodecCtx->height, 1);
//버퍼
buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
//Setup the data pointers and linesizes based on the specified image
av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize,
buffer, AV_PIX_FMT_BGRA, pCodecCtx->width, pCodecCtx->height, 1);
//첫번째 프레임을 읽고 cocos2d::Texture2D, Sprite를 생성해서 복사하기
//read frame
while (true)
{
if (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == videoStream) {
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished) {
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
}
}
av_free_packet(&packet);
break;
}
}
//to Sprite
cocos2d::Texture2D* dTex = new cocos2d::Texture2D();
if (dTex->initWithData(pFrameRGB->data[0],
pCodecCtx->width * pCodecCtx->height * 4,
cocos2d::Texture2D::PixelFormat::RGBA8888,
pCodecCtx->width,
pCodecCtx->height,
cocos2d::Size(pCodecCtx->width, pCodecCtx->height)) == false) return false;
dTex->autorelease();
v_spr = cocos2d::Sprite::createWithTexture(dTex);
this->addChild(v_spr);
//프레임 업데이트 설정
schedule(schedule_selector(LayerMovie::updateFrame), uTime);
return true;
}
void LayerMovie::updateFrame(float dt)
{
//read 1st frame
while (true)
{
if (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == videoStream) {
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished) {
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
}
}
av_free_packet(&packet);
break;
}
else
{
if (_loop) av_seek_frame(
pFormatCtx, videoStream, pFormatCtx->start_time, AVSEEK_FLAG_FRAME);
else this->removeFromParentAndCleanup(true);
return;
}
}
v_spr->getTexture()->updateWithData(
pFrameRGB->data[0], 0, 0,
pCodecCtx->width, pCodecCtx->height);
}
'cocos2dx' 카테고리의 다른 글
action)callfuncN을 이용한 트릭 (0) | 2023.03.14 |
---|---|
cocos2d observer pattern : notification center (0) | 2023.03.14 |
좌우가 연속되는 배경 횡스크롤 (0) | 2023.03.14 |
애니메이션 재생후 셀프삭제, using schedule, CardinalSpline (0) | 2023.03.14 |
particle/using action function (0) | 2023.03.14 |