~ubuntu-branches/ubuntu/quantal/mythtv/quantal

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
// -*- Mode: c++ -*-
/**
 *  DTVRecorder -- base class for Digital Television recorders
 *  Copyright (c) 2003-2004 by Brandon Beattie, Doug Larrick,
 *    Jason Hoos, and Daniel Thor Kristjansson
 *  Distributed as part of MythTV under GPL v2 and later.
 */

#ifndef DTVRECORDER_H
#define DTVRECORDER_H

#include <vector>
using namespace std;

#include <QAtomicInt>
#include <QString>

#include "streamlisteners.h"
#include "recorderbase.h"
#include "H264Parser.h"

class MPEGStreamData;
class TSPacket;
class QTime;

class DTVRecorder :
    public RecorderBase,
    public MPEGStreamListener,
    public MPEGSingleProgramStreamListener,
    public DVBMainStreamListener,
    public ATSCMainStreamListener,
    public TSPacketListener,
    public TSPacketListenerAV
{
  public:
    DTVRecorder(TVRec *rec);
    virtual ~DTVRecorder();

    virtual void SetOption(const QString &opt, const QString &value);
    virtual void SetOption(const QString &name, int value);
    virtual void SetOptionsFromProfile(
        RecordingProfile *profile, const QString &videodev,
        const QString&, const QString&);

    bool IsErrored(void) { return !_error.isEmpty(); }

    long long GetFramesWritten(void) { return _frames_written_count; }

    void SetVideoFilters(QString &/*filters*/) {;}
    void Initialize(void) {;}
    int GetVideoFd(void) { return _stream_fd; }

    virtual void SetNextRecording(const ProgramInfo*, RingBuffer*);
    virtual void SetStreamData(void);
    void SetStreamData(MPEGStreamData* sd);
    MPEGStreamData *GetStreamData(void) const { return _stream_data; }

    virtual void Reset(void);
    virtual void ClearStatistics(void);
    virtual RecordingQuality *GetRecordingQuality(void) const;

    // MPEG Stream Listener
    void HandlePAT(const ProgramAssociationTable*);
    void HandleCAT(const ConditionalAccessTable*) {}
    void HandlePMT(uint pid, const ProgramMapTable*);
    void HandleEncryptionStatus(uint /*pnum*/, bool /*encrypted*/) { }

    // MPEG Single Program Stream Listener
    void HandleSingleProgramPAT(ProgramAssociationTable *pat);
    void HandleSingleProgramPMT(ProgramMapTable *pmt);

    // ATSC Main
    void HandleSTT(const SystemTimeTable*) { UpdateCAMTimeOffset(); }
    void HandleVCT(uint /*tsid*/, const VirtualChannelTable*) {}
    void HandleMGT(const MasterGuideTable*) {}

    // DVBMainStreamListener
    void HandleTDT(const TimeDateTable*) { UpdateCAMTimeOffset(); }
    void HandleNIT(const NetworkInformationTable*) {}
    void HandleSDT(uint /*tsid*/, const ServiceDescriptionTable*) {}

    // TSPacketListener
    bool ProcessTSPacket(const TSPacket &tspacket);

    // TSPacketListenerAV
    bool ProcessVideoTSPacket(const TSPacket& tspacket);
    bool ProcessAudioTSPacket(const TSPacket& tspacket);

    // Common audio/visual processing
    bool ProcessAVTSPacket(const TSPacket &tspacket);

  protected:
    void FinishRecording(void);
    void ResetForNewFile(void);

    void HandleKeyframe(uint64_t frameNum, int64_t extra = 0);
    void HandleTimestamps(int stream_id, int64_t pts, int64_t dts);

    void BufferedWrite(const TSPacket &tspacket);

    // MPEG TS "audio only" support
    bool FindAudioKeyframes(const TSPacket *tspacket);

    // MPEG2 TS support
    bool FindMPEG2Keyframes(const TSPacket* tspacket);

    // MPEG4 AVC / H.264 TS support
    bool FindH264Keyframes(const TSPacket* tspacket);
    void HandleH264Keyframe(void);

    // MPEG2 PS support (Hauppauge PVR-x50/PVR-500)
    void FindPSKeyFrames(const uint8_t *buffer, uint len);

    // For handling other (non audio/video) packets
    bool FindOtherKeyframes(const TSPacket *tspacket);

    inline bool CheckCC(uint pid, uint cc);

    virtual QString GetSIStandard(void) const { return "mpeg"; }
    virtual void SetCAMPMT(const ProgramMapTable*) {}
    virtual void UpdateCAMTimeOffset(void) {}

    // file handle for stream
    int _stream_fd;

    QString _recording_type;

    // used for scanning pes headers for keyframes
    QTime     _audio_timer;
    uint32_t  _start_code;
    int       _first_keyframe;
    unsigned long long _last_gop_seen;
    unsigned long long _last_seq_seen;
    unsigned long long _last_keyframe_seen;
    unsigned int _audio_bytes_remaining;
    unsigned int _video_bytes_remaining;
    unsigned int _other_bytes_remaining;

    // MPEG2 parser information
    int _progressive_sequence;
    int _repeat_pict;

    // H.264 support
    bool _pes_synced;
    bool _seen_sps;
    H264Parser m_h264_parser;

    /// Wait for the a GOP/SEQ-start before sending data
    bool _wait_for_keyframe_option;

    bool _has_written_other_keyframe;

    // state tracking variables
    /// non-empty iff irrecoverable recording error detected
    QString _error;

    MPEGStreamData          *_stream_data;

    // keyframe finding buffer
    bool                  _buffer_packets;
    vector<unsigned char> _payload_buffer;

    // general recorder stuff
    mutable QMutex           _pid_lock;
    ProgramAssociationTable *_input_pat; ///< PAT on input side
    ProgramMapTable         *_input_pmt; ///< PMT on input side
    bool                     _has_no_av;

    // TS recorder stuff
    unsigned char _stream_id[0x1fff + 1];
    unsigned char _pid_status[0x1fff + 1];
    unsigned char _continuity_counter[0x1fff + 1];
    vector<TSPacket> _scratch;

    // Statistics
    bool          _use_pts; // vs use dts
    uint64_t      _ts_count[256];
    int64_t       _ts_last[256];
    int64_t       _ts_first[256];
    QDateTime     _ts_first_dt[256];
    mutable QAtomicInt _packet_count;
    mutable QAtomicInt _continuity_error_count;
    unsigned long long _frames_seen_count;
    unsigned long long _frames_written_count;

    // constants
    /// If the number of regular frames detected since the last
    /// detected keyframe exceeds this value, then we begin marking
    /// random regular frames as keyframes.
    static const uint kMaxKeyFrameDistance;
    static const unsigned char kPayloadStartSeen = 0x2;
};

inline bool DTVRecorder::CheckCC(uint pid, uint new_cnt)
{
    bool ok = ((((_continuity_counter[pid] + 1) & 0xf) == new_cnt) ||
               (_continuity_counter[pid] == new_cnt) ||
               (_continuity_counter[pid] == 0xFF));

    _continuity_counter[pid] = new_cnt & 0xf;

    return ok;
}

#endif // DTVRECORDER_H