| 217 | } |
| 218 | |
| 219 | QList<QByteArray> FileSourceFFmpegFile::getParameterSets() |
| 220 | { |
| 221 | if (!this->isFileOpened) |
| 222 | return {}; |
| 223 | |
| 224 | /* The SPS/PPS are somewhere else in containers: |
| 225 | * In mp4-container (mkv also) PPS/SPS are stored separate from frame data in global headers. |
| 226 | * To access them from libav* APIs you need to look for extradata field in AVCodecContext of |
| 227 | * AVStream which relate to needed video stream. Also extradata can have different format from |
| 228 | * standard H.264 NALs so look in MP4-container specs for format description. */ |
| 229 | const auto extradata = this->getExtradata(); |
| 230 | if (extradata.isEmpty()) |
| 231 | { |
| 232 | DEBUG_FFMPEG("Error no extradata could be found."); |
| 233 | return {}; |
| 234 | } |
| 235 | |
| 236 | QList<QByteArray> retArray; |
| 237 | |
| 238 | // Since the FFmpeg developers don't want to make it too easy, the extradata is organized |
| 239 | // differently depending on the codec. |
| 240 | auto codecID = this->ff.getCodecIDWrapper(video_stream.getCodecID()); |
| 241 | if (codecID.isHEVC()) |
| 242 | { |
| 243 | if (extradata.at(0) == 1) |
| 244 | { |
| 245 | // Internally, ffmpeg uses a custom format for the parameter sets (hvcC). |
| 246 | // The hvcC parameters come first, and afterwards, the "normal" parameter sets are sent. |
| 247 | |
| 248 | // The first 22 bytes are fixed hvcC parameter set (see hvcc_write in libavformat hevc.c) |
| 249 | auto numOfArrays = int(extradata.at(22)); |
| 250 | |
| 251 | int pos = 23; |
| 252 | for (int i = 0; i < numOfArrays; i++) |
| 253 | { |
| 254 | // The first byte contains the NAL unit type (which we don't use here). |
| 255 | pos++; |
| 256 | // int byte = (unsigned char)(extradata.at(pos++)); |
| 257 | // bool array_completeness = byte & (1 << 7); |
| 258 | // int nalUnitType = byte & 0x3f; |
| 259 | |
| 260 | // Two bytes numNalus |
| 261 | int numNalus = (unsigned char)(extradata.at(pos++)) << 7; |
| 262 | numNalus += (unsigned char)(extradata.at(pos++)); |
| 263 | |
| 264 | for (int j = 0; j < numNalus; j++) |
| 265 | { |
| 266 | // Two bytes nalUnitLength |
| 267 | int nalUnitLength = (unsigned char)(extradata.at(pos++)) << 7; |
| 268 | nalUnitLength += (unsigned char)(extradata.at(pos++)); |
| 269 | |
| 270 | // nalUnitLength bytes payload of the NAL unit |
| 271 | // This payload includes the NAL unit header |
| 272 | auto rawNAL = extradata.mid(pos, nalUnitLength); |
| 273 | retArray.append(rawNAL); |
| 274 | pos += nalUnitLength; |
| 275 | } |
| 276 | } |
no test coverage detected