source: branches/blt4/src/objects/RpMediaPlayer.cc @ 4988

Last change on this file since 4988 was 3959, checked in by gah, 11 years ago

sync with trunk

File size: 8.2 KB
Line 
1/*
2 * ======================================================================
3 *  Rappture::MediaPlayer
4 *
5 *  AUTHOR:  Derrick Kearney, Purdue University
6 *
7 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
8 * ----------------------------------------------------------------------
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 */
13
14#include <cstdlib>
15#include <cstdio>
16#include <cstring>
17#include <cmath>
18#include <fstream>
19#include <assert.h>
20
21#include "RpMediaPlayer.h"
22
23using namespace Rappture;
24
25MediaPlayer::MediaPlayer() :
26    _width (0),
27    _height (0),
28    _bitRate(400000),
29    _frameRate(25.0f),
30    _pFormatCtx(NULL),
31    _videoStream(-1),
32    _pCodecCtx(NULL),
33    _pCodec(NULL),
34    _pFrame(NULL),
35    _pFrameRGB(NULL),
36    _packet(),
37    _buffer(NULL),
38    _swsctx(NULL)
39{
40}
41
42/**
43 * Copy constructor
44 * @param MediaPlayer object to copy
45 */
46 /*
47MediaPlayer::MediaPlayer(const MediaPlayer& o)
48{}
49*/
50
51MediaPlayer::~MediaPlayer()
52{
53    // release();
54}
55
56
57bool
58MediaPlayer::init(Outcome &status, const char *filename)
59{
60    status.addContext("Rappture::MediaPlayer::init()");
61
62    /* Register all codecs and formats */
63    av_register_all();
64    return load(status, filename);
65}
66
67bool
68MediaPlayer::load(Outcome &status, const char *filename)
69{
70    status.addContext("Rappture::MediaPlayer::load()");
71
72    // Open video file
73    if(av_open_input_file(&_pFormatCtx, filename, NULL, 0, NULL)!=0) {
74        status.addError("Could not open file");
75        return false;
76    }
77
78    // Retrieve stream information
79    if(av_find_stream_info(_pFormatCtx)<0) {
80        status.addError("Could not find stream information");
81        return false;
82    }
83
84    // Dump information about file onto standard error
85    dump_format(_pFormatCtx, 0, filename, 0);
86
87    // Find the first video stream
88    _videoStream=-1;
89    for(size_t i=0; i<_pFormatCtx->nb_streams; i++) {
90        if(_pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
91            _videoStream=i;
92            break;
93        }
94    }
95
96    if(_videoStream==-1) {
97        status.addError("Did not find a video stream");
98        return false;
99    }
100
101    // Get a pointer to the codec context for the video stream
102    _pCodecCtx=_pFormatCtx->streams[_videoStream]->codec;
103
104    // Find the decoder for the video stream
105    _pCodec=avcodec_find_decoder(_pCodecCtx->codec_id);
106    if(_pCodec==NULL) {
107        status.addError("Unsupported codec");
108        return false;
109    }
110
111    // Open codec
112    if(avcodec_open(_pCodecCtx, _pCodec)<0) {
113        status.addError("Could not open codec");
114        return false;
115    }
116
117    // Allocate video frame
118    _pFrame=avcodec_alloc_frame();
119
120    // Allocate an AVFrame structure
121    _pFrameRGB=avcodec_alloc_frame();
122    if(_pFrameRGB==NULL) {
123        status.addError("Failed to allocate avcodec frame");
124        return false;
125    }
126
127    // Determine required buffer size and allocate buffer
128    int numBytes=avpicture_get_size(PIX_FMT_RGB24, _pCodecCtx->width,
129                                    _pCodecCtx->height);
130    _buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
131
132    // Assign appropriate parts of buffer to image planes in pFrameRGB
133    avpicture_fill((AVPicture *)_pFrameRGB, _buffer, PIX_FMT_RGB24,
134                    _pCodecCtx->width, _pCodecCtx->height);
135
136    /* setup sws context */
137    if (_swsctx == NULL) {
138        _swsctx = sws_getContext(_pCodecCtx->width, _pCodecCtx->height,
139                                 _pCodecCtx->pix_fmt, _pCodecCtx->width,
140                                 _pCodecCtx->height, PIX_FMT_RGB24,
141                                 SWS_BILINEAR, NULL, NULL, NULL);
142        if (_swsctx == NULL) {
143            status.addError("Cannot initialize the conversion context");
144            return false;
145        }
146    }
147
148    return true;
149}
150
151
152bool
153MediaPlayer::release()
154{
155    // status.addContext("Rappture::MediaPlayer::release()");
156
157    // Free the RGB image
158    if (_buffer) {
159        av_free(_buffer);
160        _buffer = NULL;
161    }
162
163    if (_pFrameRGB) {
164        av_free(_pFrameRGB);
165        _pFrameRGB = NULL;
166    }
167
168    // Free the YUV frame
169    if (_pFrame) {
170        av_free(_pFrame);
171        _pFrame = NULL;
172    }
173
174    // Close the codec
175    if (_pCodecCtx) {
176        avcodec_close(_pCodecCtx);
177        _pCodecCtx = NULL;
178    }
179
180    // Close the video file
181    if (_pFormatCtx) {
182        av_close_input_file(_pFormatCtx);
183        _pFormatCtx = NULL;
184    }
185
186    return true;
187}
188
189size_t
190MediaPlayer::read(Outcome &status, SimpleCharBuffer *b)
191{
192    status.addContext("Rappture::MediaPlayer::read()");
193
194    int frameFinished = 0;
195
196    while(av_read_frame(_pFormatCtx, &_packet)>=0) {
197        // Is this a packet from the video stream?
198        if(_packet.stream_index==_videoStream) {
199            // Decode video frame
200            avcodec_decode_video2(_pCodecCtx, _pFrame, &frameFinished,
201                                  &_packet);
202
203            // Did we get a video frame?
204            if (frameFinished) {
205                // Convert the image from its native format to RGB
206                sws_scale(_swsctx,
207                          (const uint8_t * const*)_pFrame->data,
208                          _pFrame->linesize, 0, _pCodecCtx->height,
209                          _pFrameRGB->data, _pFrameRGB->linesize);
210
211                __frame2ppm(b);
212                break;
213            }
214        }
215
216        // Free the packet that was allocated by av_read_frame
217        av_free_packet(&_packet);
218    }
219    return 1;
220}
221
222size_t
223MediaPlayer::nframes() const
224{
225    // status.addContext("Rappture::MediaPlayer::nframes()");
226    return 0;
227}
228/*
229int packet_queue_put(PacketQueue *q, AVPacket *pkt) {
230
231  AVPacketList *pkt1;
232  if(pkt != &flush_pkt && av_dup_packet(pkt) < 0) {
233    return -1;
234  }
235    if(packet_queue_get(&is->audioq, pkt, 1) < 0) {
236      return -1;
237    }
238    if(packet->data == flush_pkt.data) {
239      avcodec_flush_buffers(is->audio_st->codec);
240      continue;
241    }
242*/
243
244
245int
246MediaPlayer::seek(long offset, int whence)
247{
248    // status.addContext("Rappture::MediaPlayer::seek()");
249    int stream_index= -1;
250    int64_t seek_target = is->seek_pos;
251
252    if (is->videoStream >= 0) {
253        stream_index = is->videoStream;
254    } else if (is->audioStream >= 0) {
255        stream_index = is->audioStream;
256    }
257
258    if(stream_index>=0){
259        seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q,
260                      pFormatCtx->streams[stream_index]->time_base);
261    }
262    if(av_seek_frame(is->pFormatCtx, stream_index,
263                    seek_target, is->seek_flags) < 0) {
264        fprintf(stderr, "%s: error while seeking\n",
265            is->pFormatCtx->filename);
266    } else {
267        /* handle packet queues... more later... */
268        if(is->audioStream >= 0) {
269            packet_queue_flush(&is->audioq);
270            packet_queue_put(&is->audioq, &flush_pkt);
271        }
272        if(is->videoStream >= 0) {
273            packet_queue_flush(&is->videoq);
274            packet_queue_put(&is->videoq, &flush_pkt);
275        }
276    }
277    is->seek_req = 0;
278    return 0;
279}
280
281int
282MediaPlayer::tell() const
283{
284    // status.addContext("Rappture::MediaPlayer::tell()");
285    return 0;
286}
287
288size_t
289MediaPlayer::set(size_t nframes)
290{
291    // status.addContext("Rappture::MediaPlayer::set()");
292    return 0;
293}
294
295bool
296MediaPlayer::good() const
297{
298    // status.addContext("Rappture::MediaPlayer::good()");
299    return true;
300}
301
302bool
303MediaPlayer::bad() const
304{
305    // status.addContext("Rappture::MediaPlayer::bad()");
306    return false;
307}
308
309bool
310MediaPlayer::eof() const
311{
312    // status.addContext("Rappture::MediaPlayer::eof()");
313    return false;
314}
315
316void
317MediaPlayer::__frame2ppm(SimpleCharBuffer *b)
318{
319    // status.addContext("Rappture::MediaPlayer::__frame2ppm()");
320
321    // FIXME: look into using rewind or some other method that
322    //        does not free the already allocated memory. just
323    //        reuses the block.
324    b->clear();
325
326    // Write header
327    b->appendf("P6\n%d %d\n255\n", _pCodecCtx->width, _pCodecCtx->height);
328
329    // Write pixel data
330    for(int y=0; y<_pCodecCtx->height; y++) {
331        // really want to store a void*...
332        b->append((const char *)(_pFrameRGB->data[0]+y*_pFrameRGB->linesize[0]), _pCodecCtx->width*3);
333    }
334}
Note: See TracBrowser for help on using the repository browser.