summaryrefslogtreecommitdiff
path: root/rotord/libavwrapper.h
blob: a6632896f6e6d629a0a021d200ccb962da1fd850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
    #ifndef libavwrapper_H
#define libavwrapper_H

/*
 * libavwrapper.h
 * May 2012 Christopher Bruns
 * The libavwrapper class is a C++ wrapper around the poorly documented
 * libavcodec movie API used by ffmpeg.  I made extensive use of Nathan
 * Clack's implemention in the whisk project.
 *
 * The libavwrapper.h and libavwrapper.cpp files depend only on the libavcodec
 * and allied sets of libraries.  To compartmentalize and reduce dependencies
 * I placed the Vaa3d specific use of this class into a separate set of
 * source files: loadV3dFFMpeg.h/cpp
 */

////////////////////////
//now that we have guards
//instead of crashing instantly when the 2nd thread tries to encode a frame, we get an error

 //*** Error in `./rotord': corrupted double-linked list: 0x00007f3c31b1b630 ***

 //or

 //*** Error in `./rotord': double free or corruption (out): 0x00007f3bf8210080 ***
 ///////////////////////


//http://blog.tomaka17.com/2012/03/libavcodeclibavformat-tutorial/
//great to use c++11 features

#ifndef UINT64_C
#define UINT64_C(c) (c ## ULL)
#endif

#include "Poco/Mutex.h"

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/pixfmt.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>

#include <libswscale/swscale.h> //?
}

/*
#include <QFile>
#include <QNetworkAccessManager>
#include <QMutex>
#include <QUrl>
#include <QBuffer>
*/


#include <string>
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <math.h>
#include <vector>



namespace libav {



    static bool b_is_one_time_inited=false;
    // Some libavcodec calls are not reentrant
    
    void maybeInitFFMpegLib();

    static int sws_flags = SWS_BICUBIC;

// Translated to C++ by Christopher Bruns May 2012
// from ffmeg_adapt.c in whisk package by Nathan Clack, Mark Bolstadt, Michael Meeuwisse
    class decoder
    {
    public:
        enum Channel {
            RED = 0,
            GRAY = 0,
            GREEN = 1,
            BLUE = 2,
            ALPHA = 3
        };
 

        decoder(PixelFormat pixelFormat=PIX_FMT_RGB24);
        //decoder(QUrl url, PixelFormat pixelFormat=PIX_FMT_RGB24);
        void cleanup();
        virtual ~decoder();
        //bool open(QUrl url, enum PixelFormat formatParam = PIX_FMT_RGB24);
        //bool open(QIODevice& fileStream, QString& fileName, enum PixelFormat formatParam = PIX_FMT_RGB24);
        bool reinit_buffers_and_scaler();
        bool init_buffers_and_scaler();
        uint8_t getPixelIntensity(int x, int y, Channel c = GRAY) const;
        bool fetchFrame(int targetFrameIndex = 0);
        bool fetchFrame(int w,int h,int targetFrameIndex = 0);
        int getNumberOfFrames() const;
        int getWidth() const;
        int getHeight() const;
        int getNumberOfChannels() const;
        bool readNextFrame(int targetFrameIndex = 0);
        bool readNextFrameWithPacket(int targetFrameIndex, AVPacket& packet, AVFrame* pYuv);
        int seekToFrame(int targetFrameIndex = 0);

        // make certain members public, for use by Fast3DTexture class
        AVFrame *pFrameRGB;
        AVFrame *pRaw;
        AVFormatContext *container;
        AVCodecContext *pCtx;
        int videoStream;
        int previousFrameIndex;
        bool isOpen;

        bool open(std::string& fileName, enum PixelFormat formatParam = PIX_FMT_RGB24);
        bool open(char* fileName, enum PixelFormat formatParam = PIX_FMT_RGB24);

    protected:
        

        void initialize();

        bool openUsingInitializedContainer(enum PixelFormat formatParam = PIX_FMT_RGB24 );
        static bool avtry(int result, const std::string& msg);

        AVCodec *pCodec;
        uint8_t *buffer,
                *blank;
        //struct 
        SwsContext *Sctx;
        int width, height;
        PixelFormat format;
        size_t numBytes;
        int numFrames;
        int sc; // number of color channels

        // For loading from URL
        /*
        static const int ioBufferSize = 32768;
        unsigned char * ioBuffer;
        QNetworkAccessManager networkManager;
        AVIOContext* avioContext;
        QFile fileStream;
        QNetworkReply* reply;
        QBuffer fileBuffer;
        QByteArray byteArray;
        */
    };


    // TODO - finish refactoring based on
    // http://svn.gnumonks.org/trunk/21c3-video/ffmpeg/ffmpeg-0.4.9-pre1/output_example.c
    class encoder
    {
    public:
        //typedef encoder::Channel Channel;

        encoder(const char * file_name, int width, int height, float _framerate=25.0f, enum AVCodecID codec_id = CODEC_ID_H264);
        virtual ~encoder();
        void setPixelIntensity(int x, int y, int c, uint8_t value);
        void write_frame(float seconds,uint8_t *rgbdata);
        void write_frame(float seconds,uint16_t *audiodata);
        int get_audio_framesize(){ return audio_input_frame_size; }
        float get_audio_step(){return audiostep;};

    protected:
        AVFormatContext *container;
        AVCodecContext *pCtx;
        AVFrame *picture_yuv;
        AVFrame *picture_rgb;
        AVFrame *audio_frame;
        float timebase;
        struct SwsContext *Sctx;

        AVStream *audio_st;
        AVStream *video_st;

        AVCodecContext *aCtx;
        int audio_input_frame_size;
        float audiostep;
    };


    class exporter {
        public:
            virtual ~exporter(){};
            bool setup(int w,int h, int bitRate, int frameRate, std::string container);
            bool record(std::string filename);
            bool encodeFrame(unsigned char *pixels, uint16_t *samples);
            bool encodeFrame(unsigned char *pixels,AVPacket *audiopkt);  //is possible to just copy the packets?
            bool encodeFrame(unsigned char *pixels);
            bool encodeFrame(uint16_t *samples);
            void finishRecord();
            int get_audio_framesize(){return audioframesize;};
            float get_audio_step(){return audiostep;};

            AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,enum AVCodecID codec_id);
            void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st);
            int open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st);

            void write_audio_frame(AVFormatContext *oc, AVStream *st,uint16_t *samples);
            void write_audio_frame(AVFormatContext *oc, AVStream *st,AVPacket *pkt);
            void close_audio(AVFormatContext *oc, AVStream *st);

            void write_video_frame(AVFormatContext *oc, AVStream *st, uint8_t *pixels);
            void close_video(AVFormatContext *oc, AVStream *st);

        private:
            AVOutputFormat *fmt;
            AVFormatContext *oc;
            AVStream *audio_st, *video_st;
            AVCodec *audio_codec, *video_codec;
            double audio_pts, video_pts;

            struct SwsContext *sws_ctx;

            int audioframesize;
            float audiostep;
            int w;
            int h;
            int bitRate;
            int frameRate;
            std::string container;

            int outputframe;

             // video output //

            AVFrame *frame;
            AVPicture src_picture, dst_picture;
            int frame_count;
            uint8_t *outPixels;


            //************************************************************//
            // audio output //

            float t, tincr, tincr2;
            int audio_input_frame_size;


    };

    class audioloader{
        public:
            audioloader(){ready=false;sample_start=0;sample_end=0;};
            bool setup(const std::string &filename);
            AVFrame* get_frame();
            uint16_t* get_samples(int num);
            AVPacket* get_packet();
            bool close();
            bool ready;

            AVCodecContext* codecContext;
            AVFormatContext* formatContext;
            int channels; //necessary to handle final packet  -- unititialised after load/ problem?
        private:
            std::vector<uint16_t> buffer;
            AVFrame* frame;
            
            AVStream* audioStream;
            
            AVPacket packet;
            int sample_end;
            int sample_start;
            bool isPlanar;
            
    };

}



#endif // libavwrapper_H