기본적인 아이디어는 AVFrame, AVPacket을 하나의 MediaFrame에서 모두 다룰 수 있게 하고 이를 책임 사슬을 통해 전달하는 방식의 파이프라인을 구성하는 간단한 예이다.
TODO : 추가적인 수정이 필요함..., Template 사용하여 일반화도 가능 할 것 같다.
#include <iostream>
#include <libavformat/avformat.h>
enum MediaType {
FRAME,
PACKET
};
class AVFrameHandler;
class AVPacketHandler;
class MediaFrame {
public:
MediaFrame(MediaType t, AVFrameHandler* avFrameHandler = nullptr, AVPacketHandler* avPacketHandler = nullptr)
: type(t), avFrameHandler(avFrameHandler), avPacketHandler(avPacketHandler) {}
MediaType getType() const { return type; }
AVFrameHandler* getAVFrameHandler() const { return avFrameHandler; }
AVPacketHandler* getAVPacketHandler() const { return avPacketHandler; }
private:
MediaType type;
AVFrameHandler* avFrameHandler;
AVPacketHandler* avPacketHandler;
};
class FrameHandler {
public:
virtual void handleFrame(const MediaFrame& frame) = 0;
virtual ~FrameHandler() = default;
};
class AVFrameHandler : public FrameHandler {
public:
void handleFrame(const MediaFrame& frame) override {
if (frame.getType() == FRAME) {
// AVFrame 처리 로직 추가
std::cout << "Handling AVFrame" << std::endl;
} else {
std::cout << "Passing to next handler" << std::endl;
AVPacketHandler* nextHandler = frame.getAVPacketHandler();
if (nextHandler) {
nextHandler->handleFrame(frame);
}
}
}
};
class AVPacketHandler : public FrameHandler {
public:
void handleFrame(const MediaFrame& frame) override {
if (frame.getType() == PACKET) {
// AVPacket 처리 로직 추가
std::cout << "Handling AVPacket" << std::endl;
} else {
std::cout << "Passing to next handler" << std::endl;
AVFrameHandler* nextHandler = frame.getAVFrameHandler();
if (nextHandler) {
nextHandler->handleFrame(frame);
}
}
}
};
class MediaNode {
public:
MediaNode(FrameHandler* handler) : handler(handler) {}
void processFrame(const MediaFrame& frame) {
if (handler) {
handler->handleFrame(frame);
}
}
void connectTo(MediaNode* nextNode) {
if (nextNode) {
AVFrameHandler* avFrameHandler = dynamic_cast<AVFrameHandler*>(handler);
AVPacketHandler* avPacketHandler = dynamic_cast<AVPacketHandler*>(handler);
if (avFrameHandler) {
frameHandler->setAVFrameHandler(nextNode->getHandler());
} else if (avPacketHandler) {
packetHandler->setAVPacketHandler(nextNode->getHandler());
}
}
}
FrameHandler* getHandler() const {
return handler;
}
private:
FrameHandler* handler;
};
int main() {
// 미디어 그래프 구성
AVFrameHandler avFrameHandler;
AVPacketHandler avPacketHandler;
// 노드 생성
MediaNode avFrameNode(&avFrameHandler);
MediaNode avPacketNode(&avPacketHandler);
// 노드 간 연결
avFrameNode.connectTo(&avPacketNode);
// 미디어 프레임 생성 (AVFrame)
MediaFrame mediaFrameAV(FRAME, &avFrameHandler, &avPacketHandler);
// 미디어 프레임 생성 (AVPacket)
MediaFrame mediaPacketAV(PACKET, &avFrameHandler, &avPacketHandler);
// 그래프에 프레임 전달
avFrameNode.processFrame(mediaFrameAV);
avFrameNode.processFrame(mediaPacketAV);
return 0;
}