FFmpeg을 이용한 미디어 파이프라인

정병주·2023년 12월 13일
0

기본적인 아이디어는 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;
}

0개의 댓글