├── .gitignore ├── CMakeLists.txt ├── COPYING ├── README.md ├── aribstr.c ├── aribstr.h ├── aribtime.hpp ├── cdt.hpp ├── config.h.in ├── context.hpp ├── context_impl.hpp ├── crc.hpp ├── descriptor.hpp ├── descriptor ├── descriptor_base.hpp ├── service_descriptor.hpp ├── short_event_descriptor.hpp └── stream_identifier_descriptor.hpp ├── eit.hpp ├── filter.hpp ├── filter ├── cdt_section_filter.hpp ├── cdt_section_filter_impl.hpp ├── eit_section_filter.hpp ├── eit_section_filter_impl.hpp ├── filter.hpp ├── pat_section_filter.hpp ├── pat_section_filter_impl.hpp ├── pcr_filter.hpp ├── pcr_filter_impl.hpp ├── pes_filter.hpp ├── pes_filter_impl.hpp ├── pmt_section_filter.hpp ├── pmt_section_filter_impl.hpp ├── sdt_section_filter.hpp ├── sdt_section_filter_impl.hpp ├── section_filter.hpp ├── section_filter_impl.hpp ├── tot_section_filter.hpp └── tot_section_filter_impl.hpp ├── packer.hpp ├── pat.hpp ├── pes.hpp ├── picojson.h ├── pmt.hpp ├── sdt.hpp ├── section.hpp ├── section_header.hpp ├── splitter_context.hpp ├── tot.hpp ├── transport_packet.hpp ├── ts_reader.hpp ├── ts_trimmer.hpp ├── tsdivider.cpp ├── util.hpp ├── view.hpp └── wrap_around_time_stamp.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles/ 3 | cmake_install.cmake 4 | Makefile 5 | tsdivider 6 | config.h 7 | *.ts 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(tsdivider) 3 | enable_language(C CXX) 4 | set(serial "0.3.1") 5 | 6 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/") 7 | 8 | # Compile Flags 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 10 | 11 | # Boost 12 | set(Boost_USE_MULTITHREADED OFF) 13 | find_package(Boost 1.60.0 REQUIRED COMPONENTS program_options filesystem system) 14 | if(Boost_FOUND) 15 | include_directories(${Boost_INCLUDE_DIRS}) 16 | endif(Boost_FOUND) 17 | 18 | configure_file( 19 | ${CMAKE_SOURCE_DIR}/config.h.in 20 | ${CMAKE_SOURCE_DIR}/config.h 21 | ) 22 | 23 | include_directories( 24 | ./ 25 | ) 26 | 27 | add_executable( 28 | tsdivider 29 | tsdivider.cpp 30 | aribstr.c 31 | ) 32 | 33 | target_link_libraries( 34 | tsdivider 35 | ${Boost_LIBRARIES} 36 | ) 37 | 38 | install(TARGETS tsdivider RUNTIME DESTINATION "bin") 39 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TsDivider 2 | ==== 3 | 4 | TsDividerは、Transport Stream(TS)ファイルの冒頭と末尾についている別番組をカットするツールです。 5 | 6 | また、TSファイル内のメタデータ表示機能として、TSID表示機能、放送開始/終了時間を表示する機能、サービス名表示機能があります。 7 | 8 | # Usage 9 | 10 | ## TS分割 11 | ```bash 12 | $ tsdivider -i input.ts -o output.ts 13 | ``` 14 | input.tsファイルを冒頭/中央/末尾の3区間に分割し、中央の区間のみをoutput.tsに出力します。 15 | 16 | TSファイル内のEITとPMTが変更される位置に基づいて区間を決定しています。 17 | もし番組の途中でEITやPMTが変わっいても、変な位置で分割されないように、デフォルトでは300秒以上の区間は必ず残すように設定されています。 18 | 19 | ### 詳細オプション 20 | * --enable_pmt_separator bool (=1) 21 | * PMTの位置で分割します (デフォルトON) 22 | * --enable_eit_separator bool (=1) 23 | * EITの位置で分割します (デフォルトON) 24 | * --trim_threshold sec (=300) 25 | * trim_threshold秒未満の区間を、冒頭もしくは末尾と判定します (デフォルト300秒) 26 | * --overlap_front packets (=1024) 27 | * 冒頭を切り落とす際に、指定パケット分の、のりしろを残します(デフォルト1024パケット) 28 | * --overlap_back packets (=1024) 29 | * 末尾を切り落とす際に、指定パケット分の、のりしろを残します(デフォルト1024パケット) 30 | 31 | ## TSファイル情報表示 32 | ```bash 33 | $ tsdivider -i input.ts --broadcast_time --program_info --transport_stream_id --prettify 34 | ``` 35 | ### 出力例 36 | ```` 37 | { 38 | "broadcast_time": { 39 | "begin": "Sat Jan 7 23:59:31 2012 JST", 40 | "duration": 1769.8360666666667, 41 | "end": "Sun Jan 8 00:29:00 2012 JST" 42 | }, 43 | "program_info": [ 44 | { 45 | "program_number": 23608, 46 | "service_name": "TOKYO MX1", 47 | "service_provider": "" 48 | }, 49 | { 50 | "program_number": 23609, 51 | "service_name": "TOKYO MX2", 52 | "service_provider": "" 53 | }, 54 | { 55 | "program_number": 23615, 56 | "service_name": "TOKYO MX臨時", 57 | "service_provider": "" 58 | }, 59 | { 60 | "program_number": 23992, 61 | "service_name": "MXワンセグ1", 62 | "service_provider": "" 63 | }, 64 | { 65 | "program_number": 23993, 66 | "service_name": "MXワンセグ2", 67 | "service_provider": "" 68 | } 69 | ], 70 | "transport_stream_id": 32391 71 | } 72 | 73 | ```` 74 | 75 | # Install 76 | * Requirement 77 | * gcc -std=c++11 78 | * boost library 79 | 80 | ```bash 81 | $ cmake -DCMAKE_BUILD_TYPE=Release . 82 | $ make 83 | $ sudo make install 84 | ``` 85 | 86 | ## Licence 87 | 88 | Released under the GPLv3 license. 89 | 90 | 91 | ## Author 92 | 93 | [range3](https://github.com/range3/) 94 | -------------------------------------------------------------------------------- /aribstr.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "aribstr.h" 10 | 11 | #define CODE_UNKNOWN 0 // 不明なグラフィックセット(非対応) 12 | #define CODE_KANJI 1 // Kanji 13 | #define CODE_ALPHANUMERIC 2 // Alphanumeric 14 | #define CODE_HIRAGANA 3 // Hiragana 15 | #define CODE_KATAKANA 4 // Katakana 16 | #define CODE_MOSAIC_A 5 // Mosaic A 17 | #define CODE_MOSAIC_B 6 // Mosaic B 18 | #define CODE_MOSAIC_C 7 // Mosaic C 19 | #define CODE_MOSAIC_D 8 // Mosaic D 20 | #define CODE_PROP_ALPHANUMERIC 9 // Proportional Alphanumeric 21 | #define CODE_PROP_HIRAGANA 10 // Proportional Hiragana 22 | #define CODE_PROP_KATAKANA 11 // Proportional Katakana 23 | #define CODE_JIS_X0201_KATAKANA 12 // JIS X 0201 Katakana 24 | #define CODE_JIS_KANJI_PLANE_1 13 // JIS compatible Kanji Plane 1 25 | #define CODE_JIS_KANJI_PLANE_2 14 // JIS compatible Kanji Plane 2 26 | #define CODE_ADDITIONAL_SYMBOLS 15 // Additional symbols 27 | 28 | 29 | #define TCHAR char 30 | #define BYTE char 31 | #define WORD int 32 | #define DWORD int 33 | #define bool int 34 | #define true 1 35 | #define false 0 36 | #define TEXT(a) a 37 | #define _T(a) a 38 | #define CODE_SET int 39 | 40 | static int m_CodeG[4]; 41 | static int *m_pLockingGL; 42 | static int *m_pLockingGR; 43 | static int *m_pSingleGL; 44 | 45 | static BYTE m_byEscSeqCount; 46 | static BYTE m_byEscSeqIndex; 47 | static bool m_bIsEscSeqDrcs; 48 | 49 | 50 | static const DWORD AribToStringInternal(TCHAR *lpszDst, const BYTE *pSrcData, const DWORD dwSrcLen); 51 | static const DWORD ProcessCharCode(TCHAR *lpszDst, const WORD wCode, const CODE_SET CodeSet); 52 | 53 | static const DWORD PutKanjiChar(TCHAR *lpszDst, const WORD wCode); 54 | static const DWORD PutAlphanumericChar(TCHAR *lpszDst, const WORD wCode); 55 | //static const DWORD PutAlphanumericHankakuChar(TCHAR *lpszDst, const WORD wCode); 56 | static const DWORD PutHiraganaChar(TCHAR *lpszDst, const WORD wCode); 57 | static const DWORD PutKatakanaChar(TCHAR *lpszDst, const WORD wCode); 58 | static const DWORD PutJisKatakanaChar(TCHAR *lpszDst, const WORD wCode); 59 | static const DWORD PutSymbolsChar(TCHAR *lpszDst, const WORD wCode); 60 | 61 | static void ProcessEscapeSeq(const BYTE byCode); 62 | 63 | static void LockingShiftGL(const BYTE byIndexG); 64 | static void LockingShiftGR(const BYTE byIndexG); 65 | static void SingleShiftGL(const BYTE byIndexG); 66 | 67 | static const bool DesignationGSET(const BYTE byIndexG, const BYTE byCode); 68 | static const bool DesignationDRCS(const BYTE byIndexG, const BYTE byCode); 69 | 70 | static const bool abCharSizeTable[] = 71 | { 72 | false, // CODE_UNKNOWN 不明なグラフィックセット(非対応) 73 | true, // CODE_KANJI Kanji 74 | false, // CODE_ALPHANUMERIC Alphanumeric 75 | false, // CODE_HIRAGANA Hiragana 76 | false, // CODE_KATAKANA Katakana 77 | false, // CODE_MOSAIC_A Mosaic A 78 | false, // CODE_MOSAIC_B Mosaic B 79 | false, // CODE_MOSAIC_C Mosaic C 80 | false, // CODE_MOSAIC_D Mosaic D 81 | false, // CODE_PROP_ALPHANUMERIC Proportional Alphanumeric 82 | false, // CODE_PROP_HIRAGANA Proportional Hiragana 83 | false, // CODE_PROP_KATAKANA Proportional Katakana 84 | false, // CODE_JIS_X0201_KATAKANA JIS X 0201 Katakana 85 | true, // CODE_JIS_KANJI_PLANE_1 JIS compatible Kanji Plane 1 86 | true, // CODE_JIS_KANJI_PLANE_2 JIS compatible Kanji Plane 2 87 | true // CODE_ADDITIONAL_SYMBOLS Additional symbols 88 | }; 89 | 90 | typedef enum{ 91 | STR_SMALL = 0, //SSZ 92 | STR_MEDIUM, //MSZ 93 | STR_NORMAL, //NSZ 94 | STR_MICRO, //SZX 0x60 95 | STR_HIGH_W, //SZX 0x41 96 | STR_WIDTH_W, //SZX 0x44 97 | STR_W, //SZX 0x45 98 | STR_SPECIAL_1, //SZX 0x6B 99 | STR_SPECIAL_2, //SZX 0x64 100 | } STRING_SIZE; 101 | 102 | STRING_SIZE m_emStrSize; 103 | 104 | bool IsSmallCharMode(void) 105 | { 106 | bool bRet = false; 107 | switch(m_emStrSize){ 108 | case STR_SMALL: 109 | bRet = true; 110 | break; 111 | case STR_MEDIUM: 112 | bRet = true; 113 | break; 114 | case STR_NORMAL: 115 | bRet = false; 116 | break; 117 | case STR_MICRO: 118 | bRet = true; 119 | break; 120 | case STR_HIGH_W: 121 | bRet = false; 122 | break; 123 | case STR_WIDTH_W: 124 | bRet = false; 125 | break; 126 | case STR_W: 127 | bRet = false; 128 | break; 129 | case STR_SPECIAL_1: 130 | bRet = false; 131 | break; 132 | case STR_SPECIAL_2: 133 | bRet = false; 134 | break; 135 | default: 136 | break; 137 | } 138 | return bRet; 139 | } 140 | 141 | int AribToString( 142 | char *lpszDst, 143 | const char *pSrcData, 144 | const int dwSrcLen) { 145 | 146 | return AribToStringInternal(lpszDst, pSrcData, dwSrcLen); 147 | } 148 | 149 | 150 | const DWORD AribToStringInternal(TCHAR *lpszDst, 151 | const BYTE *pSrcData, const DWORD dwSrcLen) 152 | { 153 | if(!pSrcData || !dwSrcLen) { 154 | lpszDst[0] = TEXT('\0'); 155 | return 0UL; 156 | } 157 | if(!lpszDst) 158 | return 0UL; 159 | 160 | DWORD dwSrcPos = 0UL; 161 | DWORD dwDstLen = 0UL; 162 | int dwSrcData; 163 | 164 | // 状態初期設定 165 | m_byEscSeqCount = 0U; 166 | m_pSingleGL = NULL; 167 | 168 | m_CodeG[0] = CODE_KANJI; 169 | m_CodeG[1] = CODE_ALPHANUMERIC; 170 | m_CodeG[2] = CODE_HIRAGANA; 171 | m_CodeG[3] = CODE_KATAKANA; 172 | 173 | m_pLockingGL = &m_CodeG[0]; 174 | m_pLockingGR = &m_CodeG[2]; 175 | 176 | m_emStrSize = STR_NORMAL; 177 | 178 | while(dwSrcPos < dwSrcLen){ 179 | dwSrcData = pSrcData[dwSrcPos] & 0xFF; 180 | 181 | if(!m_byEscSeqCount){ 182 | 183 | // GL/GR領域 184 | if((dwSrcData >= 0x21U) && (dwSrcData <= 0x7EU)){ 185 | // GL領域 186 | const CODE_SET CurCodeSet = (m_pSingleGL)? *m_pSingleGL : *m_pLockingGL; 187 | m_pSingleGL = NULL; 188 | 189 | if(abCharSizeTable[CurCodeSet]){ 190 | // 2バイトコード 191 | if((dwSrcLen - dwSrcPos) < 2UL)break; 192 | 193 | dwDstLen += ProcessCharCode(&lpszDst[dwDstLen], ((WORD)pSrcData[dwSrcPos + 0] << 8) | (WORD)pSrcData[dwSrcPos + 1], CurCodeSet); 194 | dwSrcPos++; 195 | } 196 | else{ 197 | // 1バイトコード 198 | dwDstLen += ProcessCharCode(&lpszDst[dwDstLen], (WORD)dwSrcData, CurCodeSet); 199 | } 200 | } 201 | else if((dwSrcData >= 0xA1U) && (dwSrcData <= 0xFEU)){ 202 | // GR領域 203 | const CODE_SET CurCodeSet = *m_pLockingGR; 204 | 205 | if(abCharSizeTable[CurCodeSet]){ 206 | // 2バイトコード 207 | if((dwSrcLen - dwSrcPos) < 2UL)break; 208 | 209 | dwDstLen += ProcessCharCode(&lpszDst[dwDstLen], ((WORD)(pSrcData[dwSrcPos + 0] & 0x7FU) << 8) | (WORD)(pSrcData[dwSrcPos + 1] & 0x7FU), CurCodeSet); 210 | dwSrcPos++; 211 | } 212 | else{ 213 | // 1バイトコード 214 | dwDstLen += ProcessCharCode(&lpszDst[dwDstLen], (WORD)(dwSrcData & 0x7FU), CurCodeSet); 215 | } 216 | } 217 | else{ 218 | // 制御コード 219 | switch(dwSrcData){ 220 | case 0x0FU : LockingShiftGL(0U); break; // LS0 221 | case 0x0EU : LockingShiftGL(1U); break; // LS1 222 | case 0x19U : SingleShiftGL(2U); break; // SS2 223 | case 0x1DU : SingleShiftGL(3U); break; // SS3 224 | case 0x1BU : m_byEscSeqCount = 1U; break; // ESC 225 | case 0x89U : m_emStrSize = STR_MEDIUM; break; // MSZ 226 | case 0x8AU : m_emStrSize = STR_NORMAL; break; // NSZ 227 | case 0x20U : 228 | case 0xA0U : 229 | //SP 空白 230 | //空白は文字サイズの影響あり 231 | if( IsSmallCharMode() == false ){ 232 | strcpy(&lpszDst[dwDstLen], " "); 233 | dwDstLen += 3U; 234 | } else { 235 | lpszDst[dwDstLen++] = TEXT(' '); 236 | } 237 | break; 238 | default : break; // 非対応 239 | } 240 | } 241 | } 242 | else{ 243 | // エスケープシーケンス処理 244 | ProcessEscapeSeq(dwSrcData); 245 | } 246 | 247 | dwSrcPos++; 248 | } 249 | 250 | // 終端文字 251 | lpszDst[dwDstLen] = TEXT('\0'); 252 | 253 | return dwDstLen; 254 | } 255 | 256 | const DWORD ProcessCharCode(TCHAR *lpszDst, const WORD wCode, const CODE_SET CodeSet) 257 | { 258 | switch(CodeSet){ 259 | case CODE_KANJI : 260 | case CODE_JIS_KANJI_PLANE_1 : 261 | case CODE_JIS_KANJI_PLANE_2 : 262 | // 漢字コード出力 263 | return PutKanjiChar(lpszDst, wCode); 264 | 265 | case CODE_ALPHANUMERIC : 266 | case CODE_PROP_ALPHANUMERIC : 267 | // 英数字コード出力 268 | if( IsSmallCharMode() == false ){ 269 | //全角テーブルコード取得 270 | return PutAlphanumericChar(lpszDst, wCode); 271 | } else { 272 | //半角はそのまま出力 273 | lpszDst[0] = wCode; 274 | return 1UL; 275 | } 276 | 277 | case CODE_HIRAGANA : 278 | case CODE_PROP_HIRAGANA : 279 | // ひらがなコード出力 280 | return PutHiraganaChar(lpszDst, wCode); 281 | 282 | case CODE_PROP_KATAKANA : 283 | case CODE_KATAKANA : 284 | // カタカナコード出力 285 | return PutKatakanaChar(lpszDst, wCode); 286 | 287 | case CODE_JIS_X0201_KATAKANA : 288 | // JISカタカナコード出力 289 | return PutJisKatakanaChar(lpszDst, wCode); 290 | 291 | case CODE_ADDITIONAL_SYMBOLS : 292 | // 追加シンボルコード出力 293 | return PutSymbolsChar(lpszDst, wCode); 294 | 295 | default : 296 | return 0UL; 297 | } 298 | } 299 | 300 | const DWORD PutKanjiChar(TCHAR *lpszDst, const WORD wCode) 301 | { 302 | char code[9]; 303 | char xcode[5]; 304 | iconv_t cd; 305 | 306 | size_t inbyte = 8; 307 | size_t outbyte = sizeof(xcode); 308 | 309 | memset(xcode, '\0', sizeof(xcode)); 310 | 311 | const char *fptr; 312 | char *tptr; 313 | 314 | code[0] = 0x1BU; 315 | code[1] = 0x24U; 316 | code[2] = 0x40U; 317 | code[3] = wCode >> 8; 318 | code[4] = wCode & 0xFF; 319 | code[5] = 0x1BU; 320 | code[6] = 0x28U; 321 | code[7] = 0x4AU; 322 | code[8] = '\0'; 323 | 324 | cd = iconv_open("UTF-8","ISO-2022-JP"); 325 | 326 | fptr = code; 327 | tptr = xcode; 328 | iconv(cd, (ICONV_CONST char **)&fptr, &inbyte, &tptr, &outbyte); 329 | 330 | iconv_close(cd); 331 | 332 | strncpy(lpszDst, xcode, strlen(xcode)); 333 | 334 | return strlen(xcode); 335 | } 336 | 337 | const DWORD PutAlphanumericChar(TCHAR *lpszDst, const WORD wCode) 338 | { 339 | // 英数字全角文字コード変換 340 | static const TCHAR *acAlphanumericTable = 341 | TEXT("                ") 342 | TEXT("                ") 343 | TEXT(" !”#$%&’()*+,-./") 344 | TEXT("0123456789:;<=>?") 345 | TEXT("@ABCDEFGHIJKLMNO") 346 | TEXT("PQRSTUVWXYZ[¥]^_") 347 | TEXT(" abcdefghijklmno") 348 | TEXT("pqrstuvwxyz{|} ̄ "); 349 | 350 | #ifdef _UNICODE 351 | lpszDst[0] = acAlphanumericTableZenkaku[wCode]; 352 | 353 | return 1UL; 354 | #else 355 | lpszDst[0] = acAlphanumericTable[wCode * 3U + 0U]; 356 | lpszDst[1] = acAlphanumericTable[wCode * 3U + 1U]; 357 | lpszDst[2] = acAlphanumericTable[wCode * 3U + 2U]; 358 | 359 | return 3UL; 360 | #endif 361 | } 362 | 363 | const DWORD PutHiraganaChar(TCHAR *lpszDst, const WORD wCode) 364 | { 365 | // ひらがな文字コード変換 366 | static const TCHAR *acHiraganaTable = 367 | TEXT("                ") 368 | TEXT("                ") 369 | TEXT(" ぁあぃいぅうぇえぉおかがきぎく") 370 | TEXT("ぐけげこごさざしじすずせぜそぞた") 371 | TEXT("だちぢっつづてでとどなにぬねのは") 372 | TEXT("ばぱひびぴふぶぷへべぺほぼぽまみ") 373 | TEXT("むめもゃやゅゆょよらりるれろゎわ") 374 | TEXT("ゐゑをん   ゝゞー。「」、・ "); 375 | 376 | #ifdef _UNICODE 377 | lpszDst[0] = acHiraganaTable[wCode]; 378 | 379 | return 1UL; 380 | #else 381 | lpszDst[0] = acHiraganaTable[wCode * 3U + 0U]; 382 | lpszDst[1] = acHiraganaTable[wCode * 3U + 1U]; 383 | lpszDst[2] = acHiraganaTable[wCode * 3U + 2U]; 384 | 385 | return 3UL; 386 | #endif 387 | } 388 | 389 | const DWORD PutKatakanaChar(TCHAR *lpszDst, const WORD wCode) 390 | { 391 | // カタカナ英数字文字コード変換 392 | static const TCHAR *acKatakanaTable = 393 | TEXT("                ") 394 | TEXT("                ") 395 | TEXT(" ァアィイゥウェエォオカガキギク") 396 | TEXT("グケゲコゴサザシジスズセゼソゾタ") 397 | TEXT("ダチヂッツヅテデトドナニヌネノハ") 398 | TEXT("バパヒビピフブプヘベペホボポマミ") 399 | TEXT("ムメモャヤュユョヨラリルレロヮワ") 400 | TEXT("ヰヱヲンヴヵヶヽヾー。「」、・ "); 401 | 402 | #ifdef _UNICODE 403 | lpszDst[0] = acKatakanaTable[wCode]; 404 | 405 | return 1UL; 406 | #else 407 | lpszDst[0] = acKatakanaTable[wCode * 3U + 0U]; 408 | lpszDst[1] = acKatakanaTable[wCode * 3U + 1U]; 409 | lpszDst[2] = acKatakanaTable[wCode * 3U + 2U]; 410 | 411 | return 3UL; 412 | #endif 413 | } 414 | 415 | const DWORD PutJisKatakanaChar(TCHAR *lpszDst, const WORD wCode) 416 | { 417 | // JISカタカナ文字コード変換 418 | static const TCHAR *acJisKatakanaTable = 419 | TEXT("                ") 420 | TEXT("                ") 421 | TEXT(" 。「」、・ヲァィゥェォャュョッ") 422 | TEXT("ーアイウエオカキクケコサシスセソ") 423 | TEXT("タチツテトナニヌネノハヒフヘホマ") 424 | TEXT("ミムメモヤユヨラリルレロワン゛゜") 425 | TEXT("                ") 426 | TEXT("                "); 427 | 428 | #ifdef _UNICODE 429 | lpszDst[0] = acJisKatakanaTable[wCode]; 430 | 431 | return 1UL; 432 | #else 433 | lpszDst[0] = acJisKatakanaTable[wCode * 3U + 0U]; 434 | lpszDst[1] = acJisKatakanaTable[wCode * 3U + 1U]; 435 | lpszDst[2] = acJisKatakanaTable[wCode * 3U + 2U]; 436 | 437 | return 3UL; 438 | #endif 439 | } 440 | 441 | const DWORD PutSymbolsChar(TCHAR *lpszDst, const WORD wCode) 442 | { 443 | // 追加シンボル文字コード変換(とりあえず必要そうなものだけ) 444 | static const TCHAR *aszSymbolsTable1[] = 445 | { 446 | _T("【HV】"), _T("【SD】"), _T("【P】"), _T("【W】"), _T("【MV】"), _T("【手】"), _T("【字】"), _T("【双】"), // 0x7A50 - 0x7A57 90/48 - 90/55 447 | _T("【デ】"), _T("【S】"), _T("【二】"), _T("【多】"), _T("【解】"), _T("【SS】"), _T("【B】"), _T("【N】"), // 0x7A58 - 0x7A5F 90/56 - 90/63 448 | _T("■"), _T("●"), _T("【天】"), _T("【交】"), _T("【映】"), _T("【無】"), _T("【料】"), _T("【年齢制限】"), // 0x7A60 - 0x7A67 90/64 - 90/71 449 | _T("【前】"), _T("【後】"), _T("【再】"), _T("【新】"), _T("【初】"), _T("【終】"), _T("【生】"), _T("【販】"), // 0x7A68 - 0x7A6F 90/72 - 90/79 450 | _T("【声】"), _T("【吹】"), _T("【PPV】"), _T("(秘)"), _T("ほか") // 0x7A70 - 0x7A74 90/80 - 90/84 451 | }; 452 | 453 | static const TCHAR *aszSymbolsTable2[] = 454 | { 455 | _T("→"), _T("←"), _T("↑"), _T("↓"), _T("●"), _T("○"), _T("年"), _T("月"), // 0x7C21 - 0x7C28 92/01 - 92/08 456 | _T("日"), _T("円"), _T("㎡"), _T("㎥"), _T("㎝"), _T("㎠"), _T("㎤"), _T("0."), // 0x7C29 - 0x7C30 92/09 - 92/16 457 | _T("1."), _T("2."), _T("3."), _T("4."), _T("5."), _T("6."), _T("7."), _T("8."), // 0x7C31 - 0x7C38 92/17 - 92/24 458 | _T("9."), _T("氏"), _T("副"), _T("元"), _T("故"), _T("前"), _T("[新]"), _T("0,"), // 0x7C39 - 0x7C40 92/25 - 92/32 459 | _T("1,"), _T("2,"), _T("3,"), _T("4,"), _T("5,"), _T("6,"), _T("7,"), _T("8,"), // 0x7C41 - 0x7C48 92/33 - 92/40 460 | _T("9,"), _T("(社)"), _T("(財)"), _T("(有)"), _T("(株)"), _T("(代)"), _T("(問)"), _T("▶"), // 0x7C49 - 0x7C50 92/41 - 92/48 461 | _T("◀"), _T("〖"), _T("〗"), _T("⟐"), _T("^2"), _T("^3"), _T("(CD)"), _T("(vn)"), // 0x7C51 - 0x7C58 92/49 - 92/56 462 | _T("(ob)"), _T("(cb)"), _T("(ce"), _T("mb)"), _T("(hp)"), _T("(br)"), _T("(p)"), _T("(s)"), // 0x7C59 - 0x7C60 92/57 - 92/64 463 | _T("(ms)"), _T("(t)"), _T("(bs)"), _T("(b)"), _T("(tb)"), _T("(tp)"), _T("(ds)"), _T("(ag)"), // 0x7C61 - 0x7C68 92/65 - 92/72 464 | _T("(eg)"), _T("(vo)"), _T("(fl)"), _T("(ke"), _T("y)"), _T("(sa"), _T("x)"), _T("(sy"), // 0x7C69 - 0x7C70 92/73 - 92/80 465 | _T("n)"), _T("(or"), _T("g)"), _T("(pe"), _T("r)"), _T("(R)"), _T("(C)"), _T("(箏)"), // 0x7C71 - 0x7C78 92/81 - 92/88 466 | _T("DJ"), _T("[演]"), _T("Fax") // 0x7C79 - 0x7C7B 92/89 - 92/91 467 | }; 468 | 469 | static const TCHAR *aszSymbolsTable3[] = 470 | { 471 | _T("㈪"), _T("㈫"), _T("㈬"), _T("㈭"), _T("㈮"), _T("㈯"), _T("㈰"), _T("㈷"), // 0x7D21 - 0x7D28 93/01 - 93/08 472 | _T("㍾"), _T("㍽"), _T("㍼"), _T("㍻"), _T("№"), _T("℡"), _T("〶"), _T("○"), // 0x7D29 - 0x7D30 93/09 - 93/16 473 | _T("〔本〕"), _T("〔三〕"), _T("〔二〕"), _T("〔安〕"), _T("〔点〕"), _T("〔打〕"), _T("〔盗〕"), _T("〔勝〕"), // 0x7D31 - 0x7D38 93/17 - 93/24 474 | _T("〔敗〕"), _T("〔S〕"), _T("[投]"), _T("[捕]"), _T("[一]"), _T("[二]"), _T("[三]"), _T("[遊]"), // 0x7D39 - 0x7D40 93/25 - 93/32 475 | _T("[左]"), _T("[中]"), _T("[右]"), _T("[指]"), _T("[走]"), _T("[打]"), _T("㍑"), _T("㎏"), // 0x7D41 - 0x7D48 93/33 - 93/40 476 | _T("㎐"), _T("ha"), _T("㎞"), _T("㎢"), _T("㍱"), _T("・"), _T("・"), _T("1/2"), // 0x7D49 - 0x7D50 93/41 - 93/48 477 | _T("0/3"), _T("1/3"), _T("2/3"), _T("1/4"), _T("3/4"), _T("1/5"), _T("2/5"), _T("3/5"), // 0x7D51 - 0x7D58 93/49 - 93/56 478 | _T("4/5"), _T("1/6"), _T("5/6"), _T("1/7"), _T("1/8"), _T("1/9"), _T("1/10"), _T("☀"), // 0x7D59 - 0x7D60 93/57 - 93/64 479 | _T("☁"), _T("☂"), _T("☃"), _T("☖"), _T("☗"), _T("▽"), _T("▼"), _T("♦"), // 0x7D61 - 0x7D68 93/65 - 93/72 480 | _T("♥"), _T("♣"), _T("♠"), _T("⌺"), _T("⦿"), _T("‼"), _T("⁉"), _T("(曇/晴)"), // 0x7D69 - 0x7D70 93/73 - 93/80 481 | _T("☔"), _T("(雨)"), _T("(雪)"), _T("(大雪)"), _T("⚡"), _T("(雷雨)"), _T(" "), _T("・"), // 0x7D71 - 0x7D78 93/81 - 93/88 482 | _T("・"), _T("♬"), _T("☎") // 0x7D79 - 0x7D7B 93/89 - 93/91 483 | }; 484 | 485 | static const TCHAR *aszSymbolsTable4[] = 486 | { 487 | _T("Ⅰ"), _T("Ⅱ"), _T("Ⅲ"), _T("Ⅳ"), _T("Ⅴ"), _T("Ⅵ"), _T("Ⅶ"), _T("Ⅷ"), // 0x7E21 - 0x7E28 94/01 - 94/08 488 | _T("Ⅸ"), _T("Ⅹ"), _T("Ⅺ"), _T("Ⅻ"), _T("⑰"), _T("⑱"), _T("⑲"), _T("⑳"), // 0x7E29 - 0x7E30 94/09 - 94/16 489 | _T("⑴"), _T("⑵"), _T("⑶"), _T("⑷"), _T("⑸"), _T("⑹"), _T("⑺"), _T("⑻"), // 0x7E31 - 0x7E38 94/17 - 94/24 490 | _T("⑼"), _T("⑽"), _T("⑾"), _T("⑿"), _T("㉑"), _T("㉒"), _T("㉓"), _T("㉔"), // 0x7E39 - 0x7E40 94/25 - 94/32 491 | _T("(A)"), _T("(B)"), _T("(C)"), _T("(D)"), _T("(E)"), _T("(F)"), _T("(G)"), _T("(H)"), // 0x7E41 - 0x7E48 94/33 - 94/40 492 | _T("(I)"), _T("(J)"), _T("(K)"), _T("(L)"), _T("(M)"), _T("(N)"), _T("(O)"), _T("(P)"), // 0x7E49 - 0x7E50 94/41 - 94/48 493 | _T("(Q)"), _T("(R)"), _T("(S)"), _T("(T)"), _T("(U)"), _T("(V)"), _T("(W)"), _T("(X)"), // 0x7E51 - 0x7E58 94/49 - 94/56 494 | _T("(Y)"), _T("(Z)"), _T("㉕"), _T("㉖"), _T("㉗"), _T("㉘"), _T("㉙"), _T("㉚"), // 0x7E59 - 0x7E60 94/57 - 94/64 495 | _T("①"), _T("②"), _T("③"), _T("④"), _T("⑤"), _T("⑥"), _T("⑦"), _T("⑧"), // 0x7E61 - 0x7E68 94/65 - 94/72 496 | _T("⑨"), _T("⑩"), _T("⑪"), _T("⑫"), _T("⑬"), _T("⑭"), _T("⑮"), _T("⑯"), // 0x7E69 - 0x7E70 94/73 - 94/80 497 | _T("❶"), _T("❷"), _T("❸"), _T("❹"), _T("❺"), _T("❻"), _T("❼"), _T("❽"), // 0x7E71 - 0x7E78 94/81 - 94/88 498 | _T("❾"), _T("❿"), _T("⓫"), _T("⓬"), _T("㉛") // 0x7E79 - 0x7E7D 94/89 - 94/93 499 | }; 500 | 501 | static const TCHAR *aszSymbolsTable5[] = 502 | { 503 | _T("㐂"), _T("亭"), _T("份"), _T("仿"), _T("侚"), _T("俉"), _T("傜"), _T("儞"), // 0x7521 - 0x7528 85/01 - 85/08 504 | _T("冼"), _T("㔟"), _T("匇"), _T("卡"), _T("卬"), _T("詹"), _T("吉"), _T("呍"), // 0x7529 - 0x7530 85/09 - 85/16 505 | _T("咖"), _T("咜"), _T("咩"), _T("唎"), _T("啊"), _T("噲"), _T("囤"), _T("圳"), // 0x7531 - 0x7538 85/17 - 85/24 506 | _T("圴"), _T("塚"), _T("墀"), _T("姤"), _T("娣"), _T("婕"), _T("寬"), _T("﨑"), // 0x7539 - 0x7540 85/25 - 85/32 507 | _T("㟢"), _T("庬"), _T("弴"), _T("彅"), _T("德"), _T("怗"), _T("恵"), _T("愰"), // 0x7541 - 0x7548 85/33 - 85/40 508 | _T("昤"), _T("曈"), _T("曙"), _T("曺"), _T("曻"), _T("桒"), _T("・"), _T("椑"), // 0x7549 - 0x7550 85/41 - 85/48 509 | _T("椻"), _T("橅"), _T("檑"), _T("櫛"), _T("・"), _T("・"), _T("・"), _T("毱"), // 0x7551 - 0x7558 85/49 - 85/56 510 | _T("泠"), _T("洮"), _T("海"), _T("涿"), _T("淊"), _T("淸"), _T("渚"), _T("潞"), // 0x7559 - 0x7560 85/57 - 85/64 511 | _T("濹"), _T("灤"), _T("・"), _T("・"), _T("煇"), _T("燁"), _T("爀"), _T("玟"), // 0x7561 - 0x7568 85/65 - 85/72 512 | _T("・"), _T("珉"), _T("珖"), _T("琛"), _T("琡"), _T("琢"), _T("琦"), _T("琪"), // 0x7569 - 0x7570 85/73 - 85/80 513 | _T("琬"), _T("琹"), _T("瑋"), _T("㻚"), _T("畵"), _T("疁"), _T("睲"), _T("䂓"), // 0x7571 - 0x7578 85/81 - 85/88 514 | _T("磈"), _T("磠"), _T("祇"), _T("禮"), _T("・"), _T("・") // 0x7579 - 0x757E 85/89 - 85/94 515 | }; 516 | 517 | static const TCHAR *aszSymbolsTable6[] = 518 | { 519 | _T("・"), _T("秚"), _T("稞"), _T("筿"), _T("簱"), _T("䉤"), _T("綋"), _T("羡"), // 0x7621 - 0x7628 86/01 - 86/08 520 | _T("脘"), _T("脺"), _T("・"), _T("芮"), _T("葛"), _T("蓜"), _T("蓬"), _T("蕙"), // 0x7629 - 0x7630 86/09 - 86/16 521 | _T("藎"), _T("蝕"), _T("蟬"), _T("蠋"), _T("裵"), _T("角"), _T("諶"), _T("跎"), // 0x7631 - 0x7638 86/17 - 86/24 522 | _T("辻"), _T("迶"), _T("郝"), _T("鄧"), _T("鄭"), _T("醲"), _T("鈳"), _T("銈"), // 0x7639 - 0x7640 86/25 - 86/32 523 | _T("錡"), _T("鍈"), _T("閒"), _T("雞"), _T("餃"), _T("饀"), _T("髙"), _T("鯖"), // 0x7641 - 0x7648 86/33 - 86/40 524 | _T("鷗"), _T("麴"), _T("麵") // 0x7649 - 0x764B 86/41 - 86/43 525 | }; 526 | 527 | // シンボルを変換する 528 | if((wCode >= 0x7A50U) && (wCode <= 0x7A74U)){ 529 | strcpy(lpszDst, aszSymbolsTable1[wCode - 0x7A50U]); 530 | } 531 | else if((wCode >= 0x7C21U) && (wCode <= 0x7C7BU)){ 532 | strcpy(lpszDst, aszSymbolsTable2[wCode - 0x7C21U]); 533 | } 534 | else if((wCode >= 0x7D21U) && (wCode <= 0x7D7BU)){ 535 | strcpy(lpszDst, aszSymbolsTable3[wCode - 0x7D21U]); 536 | } 537 | else if((wCode >= 0x7E21U) && (wCode <= 0x7E7DU)){ 538 | strcpy(lpszDst, aszSymbolsTable4[wCode - 0x7E21U]); 539 | } 540 | else if((wCode >= 0x7521U) && (wCode <= 0x757EU)){ 541 | strcpy(lpszDst, aszSymbolsTable5[wCode - 0x7521U]); 542 | } 543 | else if((wCode >= 0x7621U) && (wCode <= 0x764BU)){ 544 | strcpy(lpszDst, aszSymbolsTable6[wCode - 0x7621U]); 545 | } 546 | else{ 547 | strcpy(lpszDst, TEXT("・")); 548 | } 549 | 550 | return strlen(lpszDst); 551 | } 552 | 553 | void ProcessEscapeSeq(const BYTE byCode) 554 | { 555 | // エスケープシーケンス処理 556 | switch(m_byEscSeqCount){ 557 | // 1バイト目 558 | case 1U : 559 | switch(byCode){ 560 | // Invocation of code elements 561 | case 0x6EU : LockingShiftGL(2U); m_byEscSeqCount = 0U; return; // LS2 562 | case 0x6FU : LockingShiftGL(3U); m_byEscSeqCount = 0U; return; // LS3 563 | case 0x7EU : LockingShiftGR(1U); m_byEscSeqCount = 0U; return; // LS1R 564 | case 0x7DU : LockingShiftGR(2U); m_byEscSeqCount = 0U; return; // LS2R 565 | case 0x7CU : LockingShiftGR(3U); m_byEscSeqCount = 0U; return; // LS3R 566 | 567 | // Designation of graphic sets 568 | case 0x24U : 569 | case 0x28U : m_byEscSeqIndex = 0U; break; 570 | case 0x29U : m_byEscSeqIndex = 1U; break; 571 | case 0x2AU : m_byEscSeqIndex = 2U; break; 572 | case 0x2BU : m_byEscSeqIndex = 3U; break; 573 | default : m_byEscSeqCount = 0U; return; // エラー 574 | } 575 | break; 576 | 577 | // 2バイト目 578 | case 2U : 579 | if(DesignationGSET(m_byEscSeqIndex, byCode)){ 580 | m_byEscSeqCount = 0U; 581 | return; 582 | } 583 | 584 | switch(byCode){ 585 | case 0x20 : m_bIsEscSeqDrcs = true; break; 586 | case 0x28 : m_bIsEscSeqDrcs = true; m_byEscSeqIndex = 0U; break; 587 | case 0x29 : m_bIsEscSeqDrcs = false; m_byEscSeqIndex = 1U; break; 588 | case 0x2A : m_bIsEscSeqDrcs = false; m_byEscSeqIndex = 2U; break; 589 | case 0x2B : m_bIsEscSeqDrcs = false; m_byEscSeqIndex = 3U; break; 590 | default : m_byEscSeqCount = 0U; return; // エラー 591 | } 592 | break; 593 | 594 | // 3バイト目 595 | case 3U : 596 | if(!m_bIsEscSeqDrcs){ 597 | if(DesignationGSET(m_byEscSeqIndex, byCode)){ 598 | m_byEscSeqCount = 0U; 599 | return; 600 | } 601 | } 602 | else{ 603 | if(DesignationDRCS(m_byEscSeqIndex, byCode)){ 604 | m_byEscSeqCount = 0U; 605 | return; 606 | } 607 | } 608 | 609 | if(byCode == 0x20U){ 610 | m_bIsEscSeqDrcs = true; 611 | } 612 | else{ 613 | // エラー 614 | m_byEscSeqCount = 0U; 615 | return; 616 | } 617 | break; 618 | 619 | // 4バイト目 620 | case 4U : 621 | DesignationDRCS(m_byEscSeqIndex, byCode); 622 | m_byEscSeqCount = 0U; 623 | return; 624 | } 625 | 626 | m_byEscSeqCount++; 627 | } 628 | 629 | void LockingShiftGL(const BYTE byIndexG) 630 | { 631 | // LSx 632 | m_pLockingGL = &m_CodeG[(int)byIndexG]; 633 | } 634 | 635 | void LockingShiftGR(const BYTE byIndexG) 636 | { 637 | // LSxR 638 | m_pLockingGR = &m_CodeG[(int)byIndexG]; 639 | } 640 | 641 | void SingleShiftGL(const BYTE byIndexG) 642 | { 643 | // SSx 644 | m_pSingleGL = &m_CodeG[(int)byIndexG]; 645 | } 646 | 647 | const bool DesignationGSET(const BYTE byIndexG_arg, const BYTE byCode) 648 | { 649 | int byIndexG = (int)byIndexG_arg; 650 | 651 | // Gのグラフィックセットを割り当てる 652 | switch(byCode){ 653 | case 0x42U : m_CodeG[byIndexG] = CODE_KANJI; return true; // Kanji 654 | case 0x4AU : m_CodeG[byIndexG] = CODE_ALPHANUMERIC; return true; // Alphanumeric 655 | case 0x30U : m_CodeG[byIndexG] = CODE_HIRAGANA; return true; // Hiragana 656 | case 0x31U : m_CodeG[byIndexG] = CODE_KATAKANA; return true; // Katakana 657 | case 0x32U : m_CodeG[byIndexG] = CODE_MOSAIC_A; return true; // Mosaic A 658 | case 0x33U : m_CodeG[byIndexG] = CODE_MOSAIC_B; return true; // Mosaic B 659 | case 0x34U : m_CodeG[byIndexG] = CODE_MOSAIC_C; return true; // Mosaic C 660 | case 0x35U : m_CodeG[byIndexG] = CODE_MOSAIC_D; return true; // Mosaic D 661 | case 0x36U : m_CodeG[byIndexG] = CODE_PROP_ALPHANUMERIC; return true; // Proportional Alphanumeric 662 | case 0x37U : m_CodeG[byIndexG] = CODE_PROP_HIRAGANA; return true; // Proportional Hiragana 663 | case 0x38U : m_CodeG[byIndexG] = CODE_PROP_KATAKANA; return true; // Proportional Katakana 664 | case 0x49U : m_CodeG[byIndexG] = CODE_JIS_X0201_KATAKANA; return true; // JIS X 0201 Katakana 665 | case 0x39U : m_CodeG[byIndexG] = CODE_JIS_KANJI_PLANE_1; return true; // JIS compatible Kanji Plane 1 666 | case 0x3AU : m_CodeG[byIndexG] = CODE_JIS_KANJI_PLANE_2; return true; // JIS compatible Kanji Plane 2 667 | case 0x3BU : m_CodeG[byIndexG] = CODE_ADDITIONAL_SYMBOLS; return true; // Additional symbols 668 | default : return false; // 不明なグラフィックセット 669 | } 670 | } 671 | 672 | const bool DesignationDRCS(const BYTE byIndexG_arg, const BYTE byCode) 673 | { 674 | int byIndexG = (int)byIndexG_arg; 675 | 676 | // DRCSのグラフィックセットを割り当てる 677 | switch(byCode){ 678 | case 0x40U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-0 679 | case 0x41U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-1 680 | case 0x42U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-2 681 | case 0x43U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-3 682 | case 0x44U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-4 683 | case 0x45U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-5 684 | case 0x46U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-6 685 | case 0x47U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-7 686 | case 0x48U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-8 687 | case 0x49U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-9 688 | case 0x4AU : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-10 689 | case 0x4BU : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-11 690 | case 0x4CU : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-12 691 | case 0x4DU : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-13 692 | case 0x4EU : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-14 693 | case 0x4FU : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // DRCS-15 694 | case 0x70U : m_CodeG[byIndexG] = CODE_UNKNOWN; return true; // Macro 695 | default : return false; // 不明なグラフィックセット 696 | } 697 | } 698 | -------------------------------------------------------------------------------- /aribstr.h: -------------------------------------------------------------------------------- 1 | #ifndef ARIBSTR_H 2 | #define ARIBSTR_H 1 3 | 4 | #ifdef __cplusplus 5 | extern "C"{ 6 | #endif /* __cplusplus */ 7 | 8 | int AribToString(char *lpszDst, const char *pSrcData, const int dwSrcLen); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif /* __cplusplus */ 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /aribtime.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_ARIBTIME_HPP_ 2 | #define _TSD_ARIBTIME_HPP_ 3 | 4 | #include 5 | #include "util.hpp" 6 | 7 | namespace tsd 8 | { 9 | using std::chrono::system_clock; 10 | 11 | // BCD 12 | struct aribduration 13 | { 14 | uint8_t hour; 15 | uint8_t min; 16 | uint8_t sec; 17 | public: 18 | void unpack(const char* data, size_t size) { 19 | const uint8_t* p = reinterpret_cast(data); 20 | unpack(&p, p+size); 21 | } 22 | 23 | void unpack(const uint8_t** pp, const uint8_t* pend) { 24 | const uint8_t* p = *pp; 25 | if(pend - p < 3) 26 | std::runtime_error(""); 27 | 28 | hour = bcd_to_decimal(get8(p)); 29 | p += 1; 30 | min = bcd_to_decimal(get8(p)); 31 | p += 1; 32 | sec = bcd_to_decimal(get8(p)); 33 | p += 1; 34 | 35 | *pp = p; 36 | } 37 | 38 | private: 39 | uint8_t bcd_to_decimal(uint8_t bcd) const { 40 | return (bcd >> 4)*10 + (bcd & 0x0F); 41 | } 42 | }; 43 | 44 | struct aribtime 45 | { 46 | uint16_t mjd; 47 | uint8_t hour; 48 | uint8_t min; 49 | uint8_t sec; 50 | public: 51 | void unpack(const char* data, size_t size) { 52 | const uint8_t* p = reinterpret_cast(data); 53 | unpack(&p, p+size); 54 | } 55 | 56 | void unpack(const uint8_t** pp, const uint8_t* pend) { 57 | const uint8_t* p = *pp; 58 | if(pend - p < 5) 59 | std::runtime_error(""); 60 | 61 | mjd = get16(p); 62 | p += 2; 63 | 64 | aribduration bcd; 65 | bcd.unpack(&p, pend); 66 | hour = bcd.hour; 67 | min = bcd.min; 68 | sec = bcd.sec; 69 | 70 | *pp = p; 71 | } 72 | 73 | time_t to_time_t() const { 74 | return mjd_to_time_t(mjd) + hour*60*60 + min*60 + sec - 9*60*60; 75 | } 76 | 77 | system_clock::time_point time() const { 78 | return system_clock::from_time_t(to_time_t()); 79 | } 80 | 81 | private: 82 | time_t mjd_to_time_t(uint16_t mjd) const { 83 | return (mjd - 40587)*86400; 84 | } 85 | 86 | }; 87 | 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /cdt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_CDT_HPP_ 2 | #define _TSD_CDT_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include "util.hpp" 8 | #include "descriptor.hpp" 9 | 10 | namespace tsd 11 | { 12 | class common_data_table 13 | { 14 | public: 15 | uint16_t original_network_id; 16 | uint8_t data_type; 17 | std::vector descriptors; 18 | const uint8_t* data_module_byte; 19 | size_t data_module_byte_length; 20 | 21 | public: 22 | common_data_table() {} 23 | 24 | void unpack(const char* data, size_t size) { 25 | const uint8_t* p = reinterpret_cast(data); 26 | const uint8_t* pend = p+size; 27 | 28 | original_network_id = get16(p); 29 | p += 2; 30 | data_type = get8(p); 31 | p += 1; 32 | uint16_t loop_length = get16(p) & 0x0FFF; 33 | p += 2; 34 | 35 | const uint8_t* ploop_end = p + loop_length; 36 | if(pend - p - 4 < loop_length) 37 | std::runtime_error(""); 38 | 39 | while(p < ploop_end) { 40 | descriptors.resize(descriptors.size()+1); 41 | descriptors.back().unpack(&p, ploop_end); 42 | } 43 | 44 | data_module_byte = p; 45 | data_module_byte_length = pend - 4 - p; 46 | } 47 | }; 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #cmakedefine ICONV_REQUIRES_CONST 1 5 | 6 | #ifdef ICONV_REQUIRES_CONST 7 | #define ICONV_CONST const 8 | #else 9 | #define ICONV_CONST 10 | #endif 11 | #endif 12 | 13 | #define VERSION "@serial@" 14 | -------------------------------------------------------------------------------- /context.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_CONTEXT_HPP_ 2 | #define _TSD_CONTEXT_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "util.hpp" 9 | #include "crc.hpp" 10 | 11 | #include "transport_packet.hpp" 12 | #include "view.hpp" 13 | #include "ts_trimmer.hpp" 14 | 15 | #include "boost/optional.hpp" 16 | 17 | namespace tsd { 18 | 19 | class filter; 20 | class section_filter; 21 | class pes_filter; 22 | 23 | class context 24 | { 25 | public: 26 | context(std::unique_ptr view); 27 | 28 | void clear(); 29 | 30 | void handle_packet(const transport_packet& p); 31 | 32 | void open_filter( 33 | uint16_t pid, 34 | std::unique_ptr f); 35 | void open_section_filter( 36 | uint16_t pid, 37 | std::unique_ptr f); 38 | void open_pes_filter( 39 | uint16_t pid, 40 | std::unique_ptr f); 41 | void open_pcr_filter(uint16_t pid); 42 | 43 | bool is_opened(uint16_t pid) const; 44 | 45 | view& get_view(); 46 | 47 | uint64_t get_packet_num() const { 48 | return packet_counter_; 49 | } 50 | 51 | void set_ts_trimmer(std::unique_ptr t) { 52 | ts_trimmer_ = std::move(t); 53 | } 54 | void signal_pcr(uint64_t pcr) { 55 | if(ts_trimmer_) 56 | ts_trimmer_->signal_pcr(pcr); 57 | } 58 | void signal_pmt() { 59 | if(ts_trimmer_) 60 | ts_trimmer_->signal_pmt(); 61 | } 62 | void signal_eit() { 63 | if(ts_trimmer_) 64 | ts_trimmer_->signal_eit(); 65 | } 66 | 67 | private: 68 | void set_initial_filters(); 69 | 70 | private: 71 | std::map< 72 | uint16_t, 73 | std::unique_ptr > pids_; 74 | 75 | std::unique_ptr view_; 76 | std::unique_ptr ts_trimmer_; 77 | 78 | uint64_t packet_counter_; 79 | 80 | public: 81 | boost::optional transport_stream_id; 82 | boost::optional pat; 83 | std::map program_pcr; 84 | boost::optional first_pcr; 85 | boost::optional latest_pcr; 86 | boost::optional baseline_pcr; 87 | boost::optional baseline_time; 88 | std::vector > service_descriptors; 91 | }; 92 | 93 | } 94 | 95 | #include "context_impl.hpp" 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /context_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_CONTEXT_IMPL_HPP_ 2 | #define _TSD_CONTEXT_IMPL_HPP_ 3 | 4 | #include "filter.hpp" 5 | 6 | namespace tsd { 7 | 8 | context::context(std::unique_ptr view) : 9 | view_(std::move(view)), 10 | packet_counter_(0) 11 | { 12 | set_initial_filters(); 13 | } 14 | 15 | inline 16 | void context::set_initial_filters() { 17 | open_section_filter( 18 | 0x0000, std::unique_ptr( 19 | new pat_section_filter())); 20 | open_section_filter( 21 | 0x0011, std::unique_ptr( 22 | new sdt_section_filter())); 23 | open_section_filter( 24 | 0x0012, std::unique_ptr( 25 | new eit_section_filter())); 26 | open_section_filter( 27 | 0x0026, std::unique_ptr( 28 | new eit_section_filter())); 29 | open_section_filter( 30 | 0x0027, std::unique_ptr( 31 | new eit_section_filter())); 32 | open_section_filter( 33 | 0x0014, std::unique_ptr( 34 | new tot_section_filter())); 35 | open_section_filter( 36 | 0x0029, std::unique_ptr( 37 | new cdt_section_filter())); 38 | } 39 | 40 | inline 41 | void context::clear() { 42 | pids_.clear(); 43 | ts_trimmer_.reset(); 44 | packet_counter_ = 0; 45 | transport_stream_id = boost::none; 46 | pat = boost::none; 47 | program_pcr.clear(); 48 | first_pcr = boost::none; 49 | latest_pcr = boost::none; 50 | baseline_pcr = boost::none; 51 | baseline_time = boost::none; 52 | service_descriptors.clear(); 53 | 54 | set_initial_filters(); 55 | } 56 | 57 | inline 58 | void context::handle_packet(const transport_packet& packet) { 59 | if(ts_trimmer_) 60 | ts_trimmer_->add_packet(packet); 61 | 62 | auto i_filter = pids_.find(packet.pid); 63 | if(i_filter != pids_.end()) { 64 | // find a correspondent filter 65 | auto& f = i_filter->second; 66 | f->handle_packet(*this, packet); 67 | } 68 | 69 | packet_counter_ += 1; 70 | } 71 | 72 | inline 73 | void context::open_filter( 74 | uint16_t pid, 75 | std::unique_ptr f) { 76 | auto i = pids_.lower_bound(pid); 77 | if(i != pids_.end() && !(pid < i->first)) { 78 | return; 79 | } 80 | else { 81 | pids_.emplace_hint(i, pid, std::move(f)); 82 | } 83 | } 84 | 85 | inline 86 | void context::open_section_filter( 87 | uint16_t pid, 88 | std::unique_ptr f) { 89 | open_filter(pid, std::move(f)); 90 | } 91 | 92 | inline 93 | void context::open_pes_filter( 94 | uint16_t pid, 95 | std::unique_ptr f) { 96 | open_filter(pid, std::move(f)); 97 | } 98 | 99 | inline 100 | void context::open_pcr_filter(uint16_t pid) { 101 | open_filter( 102 | pid, 103 | std::unique_ptr(new pcr_filter())); 104 | } 105 | 106 | inline 107 | bool context::is_opened(uint16_t pid) const { 108 | return pids_.count(pid); 109 | } 110 | 111 | inline 112 | view& context::get_view() { 113 | return *view_; 114 | } 115 | 116 | } 117 | 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /crc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_CRC_HPP_ 2 | #define _TSD_CRC_HPP_ 3 | 4 | #include 5 | 6 | namespace tsd 7 | { 8 | typedef boost::crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0, false, false> crc32_ts; 9 | } 10 | 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /descriptor.hpp: -------------------------------------------------------------------------------- 1 | #include "descriptor/descriptor_base.hpp" 2 | #include "descriptor/service_descriptor.hpp" 3 | #include "descriptor/short_event_descriptor.hpp" 4 | #include "descriptor/stream_identifier_descriptor.hpp" 5 | -------------------------------------------------------------------------------- /descriptor/descriptor_base.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_DESCRIPTOR_BASE_HPP_ 2 | #define _TSD_DESCRIPTOR_BASE_HPP_ 3 | 4 | namespace tsd 5 | { 6 | 7 | struct descriptor 8 | { 9 | uint8_t tag; 10 | uint8_t length; 11 | const uint8_t* pdata; 12 | 13 | void unpack(const uint8_t** pp, const uint8_t* pend) { 14 | const uint8_t* p = *pp; 15 | if(pend - p < 2) 16 | throw std::runtime_error(""); 17 | 18 | tag = get8(p); 19 | p += 1; 20 | length = get8(p); 21 | p += 1; 22 | pdata = p; 23 | p += length; 24 | 25 | *pp = p; 26 | } 27 | 28 | template 29 | const T as() const { 30 | T t; 31 | convert(t); 32 | return t; 33 | } 34 | 35 | template 36 | void convert(T& t) const { 37 | const uint8_t* p = pdata; 38 | t.unpack(&p, p+length); 39 | } 40 | }; 41 | 42 | 43 | } 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /descriptor/service_descriptor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SERVICE_DESCRIPTOR_ 2 | #define _TSD_SERVICE_DESCRIPTOR_ 3 | 4 | #include 5 | #include "util.hpp" 6 | 7 | namespace tsd 8 | { 9 | 10 | class service_descriptor 11 | { 12 | public: 13 | static const uint8_t TAG = 0x48; 14 | 15 | public: 16 | uint8_t service_type; 17 | std::string service_provider_name; 18 | std::string service_name; 19 | 20 | void unpack(const uint8_t** pp, const uint8_t* pend) { 21 | const uint8_t* p = *pp; 22 | if(pend - p < 2) 23 | std::runtime_error(""); 24 | 25 | service_type = get8(p); 26 | p += 1; 27 | size_t length = get8(p); 28 | p += 1; 29 | 30 | if(pend - p < length) 31 | std::runtime_error(""); 32 | service_provider_name.assign(p, p+length); 33 | p += length; 34 | 35 | if(pend - p < 1) 36 | std::runtime_error(""); 37 | length = get8(p); 38 | p += 1; 39 | 40 | if(pend - p < length) 41 | std::runtime_error(""); 42 | service_name.assign(p, p+length); 43 | p += length; 44 | 45 | *pp = p; 46 | } 47 | }; 48 | 49 | 50 | 51 | } 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /descriptor/short_event_descriptor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SHORT_EVENT_DESCRIPTOR_ 2 | #define _TSD_SHORT_EVENT_DESCRIPTOR_ 3 | 4 | #include 5 | #include "util.hpp" 6 | 7 | namespace tsd 8 | { 9 | 10 | class short_event_descriptor 11 | { 12 | public: 13 | static const uint8_t TAG = 0x4D; 14 | 15 | public: 16 | char iso_639_language_code[4]; 17 | std::string event_name; 18 | std::string text; 19 | 20 | void unpack(const uint8_t** pp, const uint8_t* pend) { 21 | const uint8_t* p = *pp; 22 | 23 | if(pend - p < 4) 24 | std::runtime_error(""); 25 | 26 | iso_639_language_code[0] = get8(p); 27 | p += 1; 28 | iso_639_language_code[1] = get8(p); 29 | p += 1; 30 | iso_639_language_code[2] = get8(p); 31 | p += 1; 32 | iso_639_language_code[3] = '\0'; 33 | 34 | size_t length = get8(p); 35 | p += 1; 36 | 37 | if(pend - p < length) 38 | std::runtime_error(""); 39 | event_name.assign(p, p+length); 40 | p += length; 41 | 42 | if(pend - p < 1) 43 | std::runtime_error(""); 44 | length = get8(p); 45 | p += 1; 46 | if(pend - p < length) 47 | std::runtime_error(""); 48 | text.assign(p, p+length); 49 | p += length; 50 | 51 | *pp = p; 52 | } 53 | }; 54 | 55 | 56 | 57 | } 58 | 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /descriptor/stream_identifier_descriptor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_STREAM_IDENTIFIER_DESCRIPTOR_HPP_ 2 | #define _TSD_STREAM_IDENTIFIER_DESCRIPTOR_HPP_ 3 | 4 | #include "util.hpp" 5 | 6 | namespace tsd 7 | { 8 | 9 | class stream_identifier_descriptor 10 | { 11 | public: 12 | static const uint8_t TAG = 0x52; 13 | 14 | public: 15 | uint8_t component_tag; 16 | 17 | public: 18 | void unpack(const uint8_t** pp, const uint8_t* pend) { 19 | const uint8_t* p = *pp; 20 | if(pend - p < 1) 21 | std::runtime_error(""); 22 | 23 | component_tag = get8(p); 24 | p += 1; 25 | 26 | *pp = p; 27 | } 28 | }; 29 | 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /eit.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_EIT_HPP_ 2 | #define _TSD_EIT_HPP_ 3 | 4 | #include "util.hpp" 5 | #include "descriptor.hpp" 6 | #include "aribtime.hpp" 7 | 8 | namespace tsd 9 | { 10 | 11 | 12 | struct event_information_table 13 | { 14 | struct event 15 | { 16 | uint16_t event_id; 17 | aribtime start_time; 18 | aribduration duration; 19 | uint8_t running_status; 20 | uint8_t free_ca_mode; 21 | std::vector descriptors; 22 | }; 23 | 24 | uint16_t transport_stream_id; 25 | uint16_t original_network_id; 26 | uint8_t segment_last_section_number; 27 | uint8_t last_table_id; 28 | std::vector events; 29 | 30 | void unpack(const char* data, size_t size) { 31 | const uint8_t* p = reinterpret_cast(data); 32 | const uint8_t* pend = p+size; 33 | 34 | events.clear(); 35 | 36 | transport_stream_id = get16(p); 37 | p += 2; 38 | original_network_id = get16(p); 39 | p += 2; 40 | segment_last_section_number = get8(p); 41 | p += 1; 42 | last_table_id = get8(p); 43 | p += 1; 44 | 45 | while(pend - p > 4) { 46 | events.resize(events.size()+1); 47 | auto& e = events.back(); 48 | 49 | e.event_id = get16(p); 50 | p += 2; 51 | e.start_time.unpack(&p, pend); 52 | e.duration.unpack(&p, pend); 53 | e.running_status = get8(p) >> 5; 54 | e.free_ca_mode = (get8(p) >> 4) & 0x01; 55 | size_t loop_length = get16(p) & 0x0FFF; 56 | p += 2; 57 | const uint8_t* ploop_end = p + loop_length; 58 | if(pend - p - 4 < loop_length) 59 | std::runtime_error(""); 60 | 61 | while(p < ploop_end) { 62 | e.descriptors.resize(e.descriptors.size()+1); 63 | e.descriptors.back().unpack(&p, ploop_end); 64 | } 65 | } 66 | } 67 | }; 68 | 69 | } 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /filter.hpp: -------------------------------------------------------------------------------- 1 | #include "filter/filter.hpp" 2 | #include "filter/section_filter.hpp" 3 | #include "filter/pat_section_filter.hpp" 4 | #include "filter/pmt_section_filter.hpp" 5 | #include "filter/tot_section_filter.hpp" 6 | #include "filter/sdt_section_filter.hpp" 7 | #include "filter/eit_section_filter.hpp" 8 | #include "filter/cdt_section_filter.hpp" 9 | #include "filter/pes_filter.hpp" 10 | #include "filter/pcr_filter.hpp" 11 | -------------------------------------------------------------------------------- /filter/cdt_section_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_CDT_SECTION_FILTER_HPP_ 2 | #define _TSD_CDT_SECTION_FILTER_HPP_ 3 | 4 | #include "section_header.hpp" 5 | #include "cdt.hpp" 6 | 7 | namespace tsd 8 | { 9 | class context; 10 | 11 | class cdt_section_filter : public section_filter 12 | { 13 | public: 14 | cdt_section_filter() : 15 | section_filter(true) 16 | {} 17 | virtual ~cdt_section_filter() {} 18 | 19 | protected: 20 | virtual void do_handle_section( 21 | context& c, 22 | const char* section_buffer, 23 | size_t section_length); 24 | 25 | private: 26 | bool subtable_is_changed( 27 | const section_header& header, 28 | const common_data_table& cdt); 29 | 30 | private: 31 | std::map > version_; 34 | }; 35 | 36 | } 37 | 38 | #include "filter/cdt_section_filter_impl.hpp" 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /filter/cdt_section_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_CDT_SECTION_FILTER_IMPL_HPP_ 2 | #define _TSD_CDT_SECTION_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "section.hpp" 6 | #include "cdt.hpp" 7 | 8 | namespace tsd 9 | { 10 | 11 | void cdt_section_filter::do_handle_section( 12 | context& c, 13 | const char* section_buffer, 14 | size_t section_length) { 15 | section s; 16 | s.unpack(section_buffer, section_length); 17 | common_data_table cdt; 18 | s.convert(cdt); 19 | 20 | if(!s.header.current_next_indicator) 21 | return; 22 | 23 | if(!subtable_is_changed(s.header, cdt)) 24 | return; 25 | 26 | version_ 27 | [s.header.table_id] 28 | [cdt.original_network_id] 29 | = s.header.version; 30 | } 31 | 32 | inline 33 | bool cdt_section_filter::subtable_is_changed( 34 | const section_header& header, 35 | const common_data_table& cdt) { 36 | auto i = version_.find(header.table_id); 37 | if(i == version_.end()) 38 | return true; 39 | 40 | auto j = i->second.find( 41 | cdt.original_network_id); 42 | 43 | return 44 | j == i->second.end() || 45 | j->second != header.version; 46 | } 47 | 48 | } 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /filter/eit_section_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_EIT_SECTION_FILTER_HPP_ 2 | #define _TSD_EIT_SECTION_FILTER_HPP_ 3 | 4 | #include "section_header.hpp" 5 | #include "eit.hpp" 6 | 7 | namespace tsd 8 | { 9 | class context; 10 | 11 | // Event Information Table (EIT) section 12 | // PID 0x0012, 0x0026, 0x0027 13 | // Table ID 0x4E (self stream) 14 | // Table ID 0x4F (other stream) 15 | // Table ID 0x50 - 0x5F (self stream, event schedule) 16 | // Table ID 0x60 - 0x6F (other stream, event schedule) 17 | class eit_section_filter : public section_filter 18 | { 19 | public: 20 | eit_section_filter() : 21 | section_filter(true) 22 | {} 23 | virtual ~eit_section_filter() {} 24 | 25 | protected: 26 | virtual void do_handle_section( 27 | context& c, 28 | const char* section_buffer, 29 | size_t section_length); 30 | 31 | private: 32 | bool subtable_is_changed( 33 | const section_header& header, 34 | const event_information_table& eit); 35 | 36 | private: 37 | std::map > > >version_; 42 | }; 43 | 44 | } 45 | 46 | #include "filter/eit_section_filter_impl.hpp" 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /filter/eit_section_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_EIT_SECTION_FILTER_IMPL_HPP_ 2 | #define _TSD_EIT_SECTION_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "section.hpp" 6 | #include "eit.hpp" 7 | 8 | namespace tsd 9 | { 10 | 11 | void eit_section_filter::do_handle_section( 12 | context& c, 13 | const char* section_buffer, 14 | size_t section_length) { 15 | section s; 16 | s.unpack(section_buffer, section_length); 17 | event_information_table eit; 18 | s.convert(eit); 19 | 20 | if(s.header.table_id == 0x4E) //FIXME 21 | c.get_view().print( 22 | c.get_packet_num(), 23 | s.header, 24 | eit, 25 | subtable_is_changed(s.header, eit)); 26 | 27 | if(s.header.table_id == 0x4E && 28 | s.header.section_number == 0 && 29 | !c.service_descriptors.empty() && 30 | c.service_descriptors[0].first == s.header.table_id_extension) { 31 | // FIXME: currently, the semantics of tsdivider depends on 32 | // the first service in the service description table 33 | if(subtable_is_changed(s.header, eit)){ 34 | c.signal_eit(); 35 | } 36 | } 37 | 38 | // FIXME 39 | if(s.header.section_number == s.header.last_section_number) { 40 | version_ 41 | [s.header.table_id] 42 | [s.header.table_id_extension] 43 | [eit.transport_stream_id] 44 | [eit.original_network_id] 45 | = s.header.version; 46 | } 47 | } 48 | 49 | inline 50 | bool eit_section_filter::subtable_is_changed( 51 | const section_header& header, 52 | const event_information_table& eit) { 53 | auto i = version_.find( 54 | header.table_id); 55 | if(i == version_.end()) 56 | return true; 57 | 58 | auto j = i->second.find( 59 | header.table_id_extension); 60 | if(j == i->second.end()) 61 | return true; 62 | 63 | auto k = j->second.find( 64 | eit.transport_stream_id); 65 | if(k == j->second.end()) 66 | return true; 67 | 68 | auto l = k->second.find( 69 | eit.original_network_id); 70 | 71 | return 72 | l == k->second.end() || 73 | l->second != header.version; 74 | } 75 | 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /filter/filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_FILTER_HPP_ 2 | #define _TSD_FILTER_HPP_ 3 | 4 | #include "transport_packet.hpp" 5 | 6 | namespace tsd 7 | { 8 | class context; 9 | 10 | class filter 11 | { 12 | public: 13 | filter() : 14 | last_cc_(0xf0) 15 | {} 16 | virtual ~filter() {} 17 | virtual bool is_section_filter() const { 18 | return false; 19 | } 20 | virtual void handle_packet( 21 | context& c, 22 | const transport_packet& packet) = 0; 23 | 24 | protected: 25 | bool check_continuity( 26 | const transport_packet& packet) const { 27 | uint8_t expect_cc; 28 | if(packet.has_payload()) 29 | expect_cc = (last_cc_+1) & 0x0f; 30 | else 31 | expect_cc = last_cc_; 32 | 33 | return 34 | packet.pid == 0x1FFF || // null packet PID 35 | // FIXME: discontinuity 36 | expect_cc == packet.continuity_counter; 37 | } 38 | 39 | protected: 40 | uint8_t last_cc_; 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /filter/pat_section_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PAT_SECTION_FILTER_HPP_ 2 | #define _TSD_PAT_SECTION_FILTER_HPP_ 3 | 4 | 5 | namespace tsd 6 | { 7 | class context; 8 | 9 | class pat_section_filter : public section_filter 10 | { 11 | public: 12 | pat_section_filter() : 13 | section_filter(true), 14 | last_version_(-1) 15 | {} 16 | virtual ~pat_section_filter() {} 17 | 18 | protected: 19 | virtual void do_handle_section( 20 | context& c, 21 | const char* section_buffer, 22 | size_t section_length); 23 | 24 | private: 25 | int last_version_; 26 | }; 27 | 28 | } 29 | 30 | #include "filter/pat_section_filter_impl.hpp" 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /filter/pat_section_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PAT_SECTION_FILTER_IMPL_HPP_ 2 | #define _TSD_PAT_SECTION_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "section.hpp" 6 | #include "pat.hpp" 7 | #include "filter/pmt_section_filter.hpp" 8 | 9 | namespace tsd 10 | { 11 | 12 | void pat_section_filter::do_handle_section( 13 | context& c, 14 | const char* section_buffer, 15 | size_t section_length) { 16 | section s; 17 | s.unpack(section_buffer, section_length); 18 | program_association_table pat; 19 | s.convert(pat); 20 | 21 | c.get_view().print( 22 | c.get_packet_num(), 23 | s.header, 24 | pat, 25 | last_version_ != s.header.version); 26 | 27 | if(last_version_ == s.header.version) 28 | return; 29 | 30 | c.transport_stream_id = s.header.table_id_extension; 31 | c.pat = pat; 32 | 33 | for(auto& i : pat.association) { 34 | if(i.program_number != 0) { 35 | if(!c.is_opened(i.pmt_pid)) { 36 | c.open_section_filter( 37 | i.pmt_pid, 38 | std::unique_ptr( 39 | new pmt_section_filter())); 40 | } 41 | } 42 | } 43 | 44 | last_version_ = s.header.version; 45 | } 46 | 47 | } 48 | 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /filter/pcr_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PCR_FILTER_HPP_ 2 | #define _TSD_PCR_FILTER_HPP_ 3 | 4 | namespace tsd 5 | { 6 | class context; 7 | class transport_packet; 8 | 9 | class pcr_filter : public filter 10 | { 11 | public: 12 | virtual ~pcr_filter() {} 13 | 14 | virtual void handle_packet( 15 | context& c, 16 | const transport_packet& packet); 17 | }; 18 | } 19 | 20 | #include "filter/pcr_filter_impl.hpp" 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /filter/pcr_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PCR_FILTER_IMPL_HPP_ 2 | #define _TSD_PCR_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "transport_packet.hpp" 6 | 7 | 8 | namespace tsd 9 | { 10 | 11 | void pcr_filter::handle_packet( 12 | context& c, 13 | const transport_packet& packet) { 14 | // cout << "pcr : " << packet.afield.pcr_base / 90000<< endl; 15 | if(c.pat){ 16 | for(auto& i : c.pat->association) { 17 | if(i.program_number != 0) { 18 | auto i_pcr = c.program_pcr.find(i.program_number); 19 | if(i_pcr != c.program_pcr.end()) { 20 | if(i_pcr->second == packet.pid) { 21 | c.signal_pcr(packet.afield.pcr_base); 22 | } 23 | } 24 | break; 25 | } 26 | } 27 | } 28 | 29 | c.latest_pcr = packet.afield.pcr_base; 30 | if(!c.first_pcr) 31 | c.first_pcr = packet.afield.pcr_base; 32 | } 33 | 34 | } 35 | 36 | 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /filter/pes_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PES_FILTER_HPP_ 2 | #define _TSD_PES_FILTER_HPP_ 3 | 4 | #include 5 | #include "pes.hpp" 6 | 7 | namespace tsd 8 | { 9 | class context; 10 | class transport_packet; 11 | 12 | class pes_filter : public filter 13 | { 14 | public: 15 | virtual ~pes_filter() {} 16 | 17 | virtual void handle_packet( 18 | context& c, 19 | const transport_packet& packet); 20 | 21 | private: 22 | void write_data( 23 | context& c, 24 | const char* data, 25 | size_t size, 26 | bool is_start); 27 | 28 | void handle_pes_header( 29 | context& c, 30 | const pes_header& h); 31 | 32 | void handle_pes_payload_stream( 33 | context& c, 34 | const pes_header& h, 35 | const char* data, size_t size); 36 | 37 | public: 38 | std::string pes_header_buffer_; 39 | pes_context pes_ctx_; 40 | size_t offset_; 41 | pes_header current_header_; 42 | }; 43 | } 44 | 45 | #include "filter/pes_filter_impl.hpp" 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /filter/pes_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PES_FILTER_IMPL_HPP_ 2 | #define _TSD_PES_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "util.hpp" 6 | #include "transport_packet.hpp" 7 | #include "pes.hpp" 8 | 9 | namespace tsd 10 | { 11 | 12 | void pes_filter::handle_packet( 13 | context& c, 14 | const transport_packet& packet){ 15 | write_data( 16 | c, 17 | packet.payload, 18 | packet.payload_size(), 19 | packet.payload_unit_start_indicator); 20 | } 21 | 22 | void pes_filter::write_data( 23 | context& c, 24 | const char* data, 25 | size_t size, 26 | bool is_start) { 27 | if(is_start) { 28 | pes_ctx_.init(); 29 | offset_ = 0; 30 | pes_header_buffer_.clear(); 31 | } 32 | 33 | if(pes_ctx_.get_state() == pes_context::state::skip) { 34 | return; 35 | } 36 | else if(pes_ctx_.get_state() == pes_context::state::payload) { 37 | handle_pes_payload_stream(c, current_header_, data, size); 38 | } 39 | else { 40 | pes_header_buffer_.append(data, size); 41 | pes_ctx_.execute( 42 | pes_header_buffer_.data(), 43 | pes_header_buffer_.size(), 44 | offset_); 45 | 46 | if(pes_ctx_.get_state() == pes_context::state::payload) { 47 | const uint8_t* p = reinterpret_cast( 48 | pes_header_buffer_.data()); 49 | const uint8_t* pend = p+pes_header_buffer_.size(); 50 | current_header_.unpack(&p, pend); 51 | handle_pes_header(c, current_header_); 52 | handle_pes_payload_stream( 53 | c, 54 | current_header_, 55 | reinterpret_cast(p), 56 | pend - p); 57 | } 58 | } 59 | } 60 | 61 | void pes_filter::handle_pes_header( 62 | context& c, 63 | const pes_header& h) { 64 | //pes_header::stream_type type = 65 | // pes_header::get_stream_type(h.stream_id); 66 | //if(pes_header::have_pes_header(type)) { 67 | // //cout << "---- pes packet begin ----" << endl; 68 | // //cout << "stream_type : " << (int)h.stream_id << endl; 69 | // //cout << "pes_packet_length : " << (int)h.pes_packet_length << endl; 70 | // //cout << "pes_header_data_length : " << (int)h.pes_header_data_length << endl; 71 | // if(h.has_pts()){ 72 | // cout << "pts : " << h.pts / 90000 << endl; 73 | // //cout << "pts : " << pts_sec << endl; 74 | // } 75 | // //if(h.has_dts()) 76 | // // cout << "dts : " << h.dts << endl; 77 | //} 78 | } 79 | 80 | void pes_filter::handle_pes_payload_stream( 81 | context& c, 82 | const pes_header& h, 83 | const char* data, size_t size) { 84 | 85 | } 86 | 87 | } 88 | 89 | 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /filter/pmt_section_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PMT_SECTION_FILTER_HPP_ 2 | #define _TSD_PMT_SECTION_FILTER_HPP_ 3 | 4 | namespace tsd 5 | { 6 | class context; 7 | 8 | class pmt_section_filter : public section_filter 9 | { 10 | public: 11 | pmt_section_filter() : 12 | section_filter(true), 13 | last_version_(-1) 14 | {} 15 | virtual ~pmt_section_filter() {} 16 | 17 | protected: 18 | virtual void do_handle_section( 19 | context& c, 20 | const char* section_buffer, 21 | size_t section_length); 22 | 23 | private: 24 | int last_version_; 25 | }; 26 | 27 | } 28 | 29 | #include "filter/pmt_section_filter_impl.hpp" 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /filter/pmt_section_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PMT_SECTION_FILTER_IMPL_HPP_ 2 | #define _TSD_PMT_SECTION_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "section.hpp" 6 | #include "pmt.hpp" 7 | #include "filter/pes_filter.hpp" 8 | 9 | namespace tsd 10 | { 11 | 12 | void pmt_section_filter::do_handle_section( 13 | context& c, 14 | const char* section_buffer, 15 | size_t section_length) { 16 | section s; 17 | s.unpack(section_buffer, section_length); 18 | program_map_table pmt; 19 | s.convert(pmt); 20 | 21 | c.get_view().print( 22 | c.get_packet_num(), 23 | s.header, 24 | pmt, 25 | last_version_ != s.header.version); 26 | 27 | if(last_version_ == s.header.version) 28 | return ; 29 | 30 | if(!c.is_opened(pmt.pcr_pid)) { 31 | c.open_pcr_filter(pmt.pcr_pid); 32 | } 33 | 34 | for(auto& i : c.pat->association) { 35 | if(i.program_number != 0) { 36 | if(i.program_number == s.header.table_id_extension) { 37 | c.signal_pmt(); 38 | } 39 | break; 40 | } 41 | } 42 | 43 | c.program_pcr[s.header.table_id_extension] = pmt.pcr_pid; 44 | 45 | //for(auto& pe : pmt.program_elements) { 46 | // if(pe.stream_type == 0x02) { 47 | // // video 48 | // if(!c.is_opened(pe.elementary_pid)) { 49 | // c.open_pes_filter( 50 | // pe.elementary_pid, 51 | // std::unique_ptr( 52 | // new pes_filter())); 53 | // } 54 | // } 55 | //} 56 | 57 | last_version_ = s.header.version; 58 | } 59 | 60 | } 61 | 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /filter/sdt_section_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SDT_SECTION_FILTER_HPP_ 2 | #define _TSD_SDT_SECTION_FILTER_HPP_ 3 | 4 | #include 5 | 6 | namespace tsd 7 | { 8 | class context; 9 | 10 | // Service Description Table (SDT) 11 | // PID 0x0011 12 | // Table ID 0x42 (self stream) 0x46 (other stream) 13 | class sdt_section_filter : public section_filter 14 | { 15 | public: 16 | sdt_section_filter() : 17 | section_filter(true) 18 | {} 19 | virtual ~sdt_section_filter() {} 20 | 21 | protected: 22 | virtual void do_handle_section( 23 | context& c, 24 | const char* section_buffer, 25 | size_t section_length); 26 | 27 | private: 28 | bool is_changed( 29 | const section_header& header, 30 | const service_description_table& sdt) const { 31 | auto i = version_.find( 32 | std::make_tuple( 33 | header.table_id, 34 | header.table_id_extension, 35 | sdt.original_network_id)); 36 | return i == version_.end() || i->second != header.version; 37 | } 38 | 39 | private: 40 | std::map< 41 | std::tuple< 42 | uint8_t, // table_id 43 | uint16_t, // table_id_extension 44 | uint16_t>, // original_network_id 45 | uint8_t> version_; 46 | }; 47 | 48 | } 49 | 50 | #include "filter/sdt_section_filter_impl.hpp" 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /filter/sdt_section_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SDT_SECTION_FILTER_IMPL_HPP_ 2 | #define _TSD_SDT_SECTION_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "section.hpp" 6 | #include "sdt.hpp" 7 | 8 | namespace tsd 9 | { 10 | 11 | void sdt_section_filter::do_handle_section( 12 | context& c, 13 | const char* section_buffer, 14 | size_t section_length) { 15 | section s; 16 | s.unpack(section_buffer, section_length); 17 | service_description_table sdt; 18 | s.convert(sdt); 19 | 20 | bool changed = is_changed(s.header, sdt); 21 | 22 | c.get_view().print( 23 | c.get_packet_num(), 24 | s.header, 25 | sdt, 26 | changed); 27 | 28 | if(changed) { 29 | if(s.header.table_id == 0x42) { 30 | c.service_descriptors.clear(); 31 | for(auto& service : sdt.services) { 32 | for(auto& d : service.descriptors) { 33 | if(d.tag == 0x48) { 34 | c.service_descriptors.push_back( 35 | std::make_pair( 36 | service.service_id, 37 | d.as())); 38 | } 39 | } 40 | } 41 | } 42 | 43 | version_[ 44 | std::make_tuple( 45 | s.header.table_id, 46 | s.header.table_id_extension, 47 | sdt.original_network_id)] = s.header.version; 48 | } 49 | } 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /filter/section_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SECTION_FILTER_HPP_ 2 | #define _TSD_SECTION_FILTER_HPP_ 3 | 4 | 5 | namespace tsd 6 | { 7 | class context; 8 | class transport_packet; 9 | 10 | class section_filter : public filter 11 | { 12 | public: 13 | section_filter() : 14 | filter(), 15 | do_crc_check_(false) 16 | {} 17 | section_filter( 18 | bool do_crc_check) : 19 | filter(), 20 | do_crc_check_(do_crc_check) 21 | {} 22 | 23 | virtual ~section_filter() {} 24 | virtual bool is_section_filter() const { 25 | return true; 26 | } 27 | 28 | virtual void handle_packet( 29 | context& c, 30 | const transport_packet& packet); 31 | 32 | private: 33 | void write_data( 34 | context& c, 35 | const char* data, 36 | size_t size, 37 | bool is_start); 38 | 39 | protected: 40 | void handle_section( 41 | context& c, 42 | const char* section_buffer, 43 | size_t section_length); 44 | 45 | virtual void do_handle_section( 46 | context& c, 47 | const char* section_buffer, 48 | size_t section_length) {} 49 | 50 | protected: 51 | std::string section_buffer_; 52 | bool do_crc_check_; 53 | }; 54 | } 55 | 56 | #include "filter/section_filter_impl.hpp" 57 | 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /filter/section_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SECTION_FILTER_IMPL_HPP_ 2 | #define _TSD_SECTION_FILTER_IMPL_HPP_ 3 | 4 | #include "context.hpp" 5 | #include "transport_packet.hpp" 6 | 7 | namespace tsd 8 | { 9 | 10 | void section_filter::handle_packet( 11 | context& c, 12 | const transport_packet& packet) { 13 | auto p = packet.payload; 14 | auto pend = p + packet.payload_size(); 15 | auto cc_ok = check_continuity(packet); 16 | 17 | last_cc_ = packet.continuity_counter; 18 | 19 | if(packet.payload_unit_start_indicator) { 20 | // pointer field present 21 | auto pf = packet.pointer_field(); 22 | p += 1; 23 | if(pf > pend - p) 24 | return; 25 | 26 | if(pf > 0 && cc_ok) { 27 | // write remaining section bytes 28 | write_data(c, p, pf, false); 29 | } 30 | 31 | p += pf; 32 | if(p < pend) { 33 | write_data(c, p, pend - p, true); 34 | } 35 | } 36 | else { 37 | if(cc_ok) { 38 | write_data(c, p, pend - p, false); 39 | } 40 | } 41 | } 42 | 43 | void section_filter::write_data( 44 | context& c, 45 | const char* data, 46 | size_t size, 47 | bool is_start) { 48 | if(is_start) { 49 | section_buffer_.assign(data, size); 50 | } 51 | else { 52 | section_buffer_.append(data, size); 53 | } 54 | 55 | if(section_buffer_.size() >= 3) { 56 | uint16_t section_length = 57 | (get16(section_buffer_.data()+1) & 0x0FFF) + 3; 58 | if(section_length > 4096) { 59 | return; //too long 60 | } 61 | if(section_buffer_.size() >= section_length) { 62 | bool crc_valid = true; 63 | if(do_crc_check_) { 64 | if(section_length < 4) 65 | return; 66 | uint32_t crc32 = get32(section_buffer_.data()+section_length-4); 67 | crc32_ts crc_calc; 68 | crc_calc.process_bytes( 69 | section_buffer_.data(), 70 | section_length-4); 71 | crc_valid = (crc32 == crc_calc()); 72 | } 73 | 74 | if(crc_valid) { 75 | handle_section(c, section_buffer_.data(), section_length); 76 | } 77 | } 78 | } 79 | } 80 | 81 | inline 82 | void section_filter::handle_section( 83 | context& c, 84 | const char* section_buffer, 85 | size_t section_length) { 86 | //DEBUG 87 | //cerr << "-----section dump-----" << endl; 88 | //tsd::hexdump(section_buffer, section_length, std::cerr); 89 | do_handle_section(c, section_buffer, section_length); 90 | } 91 | 92 | } 93 | 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /filter/tot_section_filter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_TOT_SECTION_FILTER_HPP_ 2 | #define _TSD_TOT_SECTION_FILTER_HPP_ 3 | 4 | namespace tsd 5 | { 6 | class context; 7 | 8 | // time offset section (or time data section) 9 | // tot and tdt are assigned to the same pid (0x0014) 10 | class tot_section_filter : public section_filter 11 | { 12 | public: 13 | tot_section_filter() : 14 | section_filter(false) 15 | {} 16 | virtual ~tot_section_filter() {} 17 | 18 | protected: 19 | virtual void do_handle_section( 20 | context& c, 21 | const char* section_buffer, 22 | size_t section_length); 23 | }; 24 | 25 | } 26 | 27 | #include "filter/tot_section_filter_impl.hpp" 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /filter/tot_section_filter_impl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_TOT_SECTION_FILTER_IMPL_HPP_ 2 | #define _TSD_TOT_SECTION_FILTER_IMPL_HPP_ 3 | 4 | #include 5 | #include "context.hpp" 6 | #include "section.hpp" 7 | #include "tot.hpp" 8 | 9 | namespace tsd 10 | { 11 | 12 | void tot_section_filter::do_handle_section( 13 | context& c, 14 | const char* section_buffer, 15 | size_t section_length) { 16 | section s; 17 | s.unpack(section_buffer, section_length); 18 | time_offset_table tot; 19 | s.convert(tot); 20 | 21 | c.get_view().print( 22 | c.get_packet_num(), 23 | s.header, 24 | tot); 25 | 26 | if(!c.baseline_time && c.latest_pcr) { 27 | c.baseline_time = tot.time.to_time_t(); 28 | c.baseline_pcr = *c.latest_pcr; 29 | } 30 | } 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /packer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PACKER_HPP_ 2 | #define _TSD_PACKER_HPP_ 3 | 4 | #include 5 | 6 | namespace tsd 7 | { 8 | class packer 9 | { 10 | public: 11 | packer(std::ostream& ost) : 12 | ost_(ost) 13 | {} 14 | 15 | void pack8(uint8_t d) { 16 | pack(d); 17 | } 18 | void pack16(uint16_t d) { 19 | pack(d); 20 | } 21 | void pack32(uint32_t d) { 22 | pack(d); 23 | } 24 | void pack64(uint64_t d) { 25 | pack(d); 26 | } 27 | 28 | void pack(uint8_t d) { 29 | ost_.write(reinterpret_cast(&d), 1); 30 | } 31 | 32 | void pack(uint16_t d) { 33 | pack(static_cast(d >> 8)); 34 | pack(static_cast(d & 0xFF)); 35 | } 36 | 37 | void pack(uint32_t d) { 38 | pack(static_cast(d >> 16)); 39 | pack(static_cast(d & 0xFFFF)); 40 | } 41 | 42 | void pack(uint64_t d) { 43 | pack(static_cast(d >> 32)); 44 | pack(static_cast(d & 0xFFFFFFFF)); 45 | } 46 | 47 | void pack_bytes(const char* data, size_t size) { 48 | ost_.write(data, size); 49 | } 50 | 51 | void pack_bytes(const uint8_t* data, size_t size) { 52 | pack_bytes(reinterpret_cast(data), size); 53 | } 54 | 55 | void pack_fill(size_t n, uint8_t d) { 56 | for(; n > 0; --n) 57 | pack(d); 58 | } 59 | 60 | private: 61 | std::ostream& ost_; 62 | }; 63 | 64 | } 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /pat.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PAT_HPP_ 2 | #define _TSD_PAT_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include "util.hpp" 8 | 9 | namespace tsd 10 | { 11 | class program_association_table 12 | { 13 | public: 14 | struct association_pair 15 | { 16 | association_pair(uint16_t pnum, uint16_t pmt) : 17 | program_number(pnum), 18 | pmt_pid(pmt) {} 19 | 20 | uint16_t program_number; 21 | uint16_t pmt_pid; 22 | }; 23 | public: 24 | std::vector association; 25 | 26 | public: 27 | program_association_table() {} 28 | 29 | void unpack(const char* data, size_t size) { 30 | const uint8_t* p = reinterpret_cast(data); 31 | const uint8_t* pend = p+size; 32 | 33 | while(pend - p >= 4+4) { 34 | association.push_back( 35 | association_pair(get16(p), get16(p+2) & 0x1FFF)); 36 | p += 4; 37 | } 38 | } 39 | }; 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /pes.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PES_HPP_ 2 | #define _TSD_PES_HPP_ 3 | 4 | #include "util.hpp" 5 | 6 | namespace tsd 7 | { 8 | 9 | class pes_header 10 | { 11 | public: 12 | enum class stream_type { 13 | program_stream_map, 14 | private_stream_1, 15 | padding_stream, 16 | private_stream_2, 17 | audio_stream, 18 | video_stream, 19 | ecm_stream, 20 | emm_stream, 21 | dsmcc_stream, 22 | iso_iec_13522_stream, 23 | itu_t_rec_h_222_1_type_a, 24 | itu_t_rec_h_222_1_type_b, 25 | itu_t_rec_h_222_1_type_c, 26 | itu_t_rec_h_222_1_type_d, 27 | itu_t_rec_h_222_1_type_e, 28 | ancillary_stream, 29 | reserved_data_stream, 30 | program_stream_directory, 31 | unknown_stream_type 32 | }; 33 | 34 | public: 35 | static constexpr uint8_t packet_start_code_prefix[3] = { 36 | 0x00, 0x00, 0x01 37 | }; 38 | 39 | static bool check_packet_start(const uint8_t* p) { 40 | return 41 | get8(p) == packet_start_code_prefix[0] && 42 | get8(p+1) == packet_start_code_prefix[1] && 43 | get8(p+2) == packet_start_code_prefix[2]; 44 | } 45 | 46 | static stream_type get_stream_type(uint8_t stream_id) { 47 | switch(stream_id) { 48 | case 0xBC: 49 | return stream_type::program_stream_map; 50 | case 0xBD: 51 | return stream_type::private_stream_1; 52 | case 0xBE: 53 | return stream_type::padding_stream; 54 | case 0xBF: 55 | return stream_type::private_stream_2; 56 | case 0xC0 ... 0xDF: 57 | return stream_type::audio_stream; 58 | case 0xE0 ... 0xEF: 59 | return stream_type::video_stream; 60 | case 0xF0: 61 | return stream_type::ecm_stream; 62 | case 0xF1: 63 | return stream_type::emm_stream; 64 | case 0xF2: 65 | return stream_type::dsmcc_stream; 66 | case 0xF3: 67 | return stream_type::iso_iec_13522_stream; 68 | case 0xF4: 69 | return stream_type::itu_t_rec_h_222_1_type_a; 70 | case 0xF5: 71 | return stream_type::itu_t_rec_h_222_1_type_b; 72 | case 0xF6: 73 | return stream_type::itu_t_rec_h_222_1_type_c; 74 | case 0xF7: 75 | return stream_type::itu_t_rec_h_222_1_type_d; 76 | case 0xF8: 77 | return stream_type::itu_t_rec_h_222_1_type_e; 78 | case 0xF9: 79 | return stream_type::ancillary_stream; 80 | case 0xFA ... 0xFE: 81 | return stream_type::reserved_data_stream; 82 | case 0xFF: 83 | return stream_type::program_stream_directory; 84 | default: 85 | return stream_type::unknown_stream_type; 86 | } 87 | } 88 | 89 | static bool have_pes_header(stream_type type) { 90 | return type != stream_type::program_stream_map && 91 | type != stream_type::padding_stream && 92 | type != stream_type::private_stream_2 && 93 | type != stream_type::ecm_stream && 94 | type != stream_type::emm_stream && 95 | type != stream_type::program_stream_directory && 96 | type != stream_type::dsmcc_stream && 97 | type != stream_type::itu_t_rec_h_222_1_type_e; 98 | } 99 | 100 | public: 101 | uint8_t stream_id; 102 | uint16_t pes_packet_length; 103 | uint16_t pes_header_block; 104 | uint8_t pes_header_data_length; 105 | uint64_t pts; 106 | uint64_t dts; 107 | uint32_t escr_base; 108 | uint16_t escr_extension; 109 | uint32_t es_rate; 110 | uint8_t trick_mode; 111 | uint8_t additional_copy_info; 112 | uint16_t previous_pes_packet_crc; 113 | std::string pes_extension_block; 114 | 115 | void unpack(const uint8_t** pp, const uint8_t* pend) { 116 | const uint8_t* p = *pp; 117 | const uint8_t* pheader_end; 118 | if(pend - p < 6) 119 | std::runtime_error(""); 120 | if(!check_packet_start(p)) 121 | std::runtime_error(""); 122 | 123 | p += 3; 124 | stream_id = get8(p); 125 | p += 1; 126 | pes_packet_length = get16(p); 127 | p += 2; 128 | 129 | stream_type type = get_stream_type(stream_id); 130 | if(have_pes_header(type)) { 131 | if(pend - p < 3) 132 | std::runtime_error(""); 133 | pes_header_block = get16(p); 134 | p += 2; 135 | pes_header_data_length = get8(p); 136 | p += 1; 137 | 138 | if(pend - p < pes_header_data_length) 139 | std::runtime_error(""); 140 | 141 | pheader_end = p + pes_header_data_length; 142 | 143 | if(has_pts()) { 144 | pts = (get8(p) & 0x0E) << 29; 145 | p += 1; 146 | pts |= (get16(p) & 0xFFFE) << 14; 147 | p += 2; 148 | pts |= (get16(p) & 0xFFFE) >> 1; 149 | p += 2; 150 | 151 | if(has_dts()) { 152 | dts = (get8(p) & 0x0E) << 29; 153 | p += 1; 154 | dts |= (get16(p) & 0xFFFE) << 14; 155 | p += 2; 156 | dts |= (get16(p) & 0xFFFE) >> 1; 157 | p += 2; 158 | } 159 | } 160 | 161 | if(escr_flag()){ 162 | //FIXME 163 | p += 6; 164 | } 165 | if(es_rate_flag()){ 166 | es_rate = (get16(p) & 0x7FFF) << 7; 167 | p += 2; 168 | es_rate |= (get8(p) & 0xFE) >> 1; 169 | p += 1; 170 | } 171 | if(dsm_trick_mode_flag()) { 172 | trick_mode = get8(p); 173 | p += 1; 174 | } 175 | if(additional_copy_info_flag()) { 176 | additional_copy_info = get8(p) & 0x7F; 177 | p += 1; 178 | } 179 | if(pes_crc_flag()) { 180 | previous_pes_packet_crc = get16(p); 181 | p += 2; 182 | } 183 | if(pes_extension_flag()) { 184 | // include padding... 185 | pes_extension_block.assign( 186 | reinterpret_cast(p), 187 | pend-p); 188 | } 189 | p = pheader_end; 190 | } 191 | *pp = p; 192 | } 193 | 194 | uint16_t pes_scrambling_control() const { 195 | return (pes_header_block & 0x3000) >> 12; 196 | } 197 | uint16_t pes_priority() const { 198 | return pes_header_block & 0x0800; 199 | } 200 | uint16_t data_alignment_indicator() const { 201 | return pes_header_block & 0x0400; 202 | } 203 | uint16_t copyright() const { 204 | return pes_header_block & 0x0200; 205 | } 206 | uint16_t original_or_copy() const { 207 | return pes_header_block & 0x0100; 208 | } 209 | uint16_t pts_dts_flags() const { 210 | return (pes_header_block & 0x00C0) >> 6; 211 | } 212 | uint16_t escr_flag() const { 213 | return pes_header_block & 0x0020; 214 | } 215 | uint16_t es_rate_flag() const { 216 | return pes_header_block & 0x0010; 217 | } 218 | uint16_t dsm_trick_mode_flag() const { 219 | return pes_header_block & 0x0008; 220 | } 221 | uint16_t additional_copy_info_flag() const { 222 | return pes_header_block & 0x0004; 223 | } 224 | uint16_t pes_crc_flag() const { 225 | return pes_header_block & 0x0002; 226 | } 227 | uint16_t pes_extension_flag() const { 228 | return pes_header_block & 0x0001; 229 | } 230 | 231 | bool has_pts() const { 232 | return pts_dts_flags() & 0x02; 233 | } 234 | bool has_dts() const { 235 | return pts_dts_flags() & 0x01; 236 | } 237 | }; 238 | 239 | class pes_context 240 | { 241 | public: 242 | enum class state { 243 | header, 244 | pes_header, 245 | pes_header_data, 246 | payload, 247 | skip 248 | }; 249 | 250 | public: 251 | void init() { 252 | state_ = state::header; 253 | } 254 | 255 | void execute(const char* data, size_t size, size_t& off) { 256 | const uint8_t* pbegin = reinterpret_cast(data); 257 | const uint8_t* p = pbegin + off; 258 | const uint8_t* pend = pbegin + size; 259 | 260 | while(p < pend) { 261 | switch(state_) { 262 | case state::header: 263 | { 264 | if(pend - p < 6) { 265 | off = p - pbegin; 266 | return; 267 | } 268 | if(!pes_header::check_packet_start(p)) { 269 | state_ = state::skip; 270 | continue; 271 | } 272 | p += 3; 273 | uint8_t stream_id = get8(p); 274 | p += 3; 275 | 276 | pes_header::stream_type type = 277 | pes_header::get_stream_type(stream_id); 278 | if(pes_header::have_pes_header(type)) { 279 | state_ = state::pes_header; 280 | } 281 | else if(type == pes_header::stream_type::padding_stream) { 282 | state_ = state::skip; 283 | } 284 | else { 285 | state_ = state::payload; 286 | } 287 | } break; 288 | case state::pes_header: 289 | { 290 | if(pend - p < 3) { 291 | off = p - pbegin; 292 | return; 293 | } 294 | p += 2; 295 | pes_header_data_length_ = get8(p); 296 | p += 1; 297 | state_ = state::pes_header_data; 298 | } break; 299 | case state::pes_header_data: 300 | { 301 | if(pend - p < pes_header_data_length_) { 302 | off = p - pbegin; 303 | return; 304 | } 305 | p += pes_header_data_length_; 306 | state_ = state::payload; 307 | } break; 308 | case state::payload: 309 | { 310 | p = pend; 311 | } break; 312 | case state::skip: 313 | { 314 | p = pend; 315 | } break; 316 | } 317 | } 318 | off = p - pbegin; 319 | } 320 | 321 | const state& get_state() const { 322 | return state_; 323 | } 324 | 325 | private: 326 | state state_; 327 | uint16_t pes_header_data_length_; 328 | }; 329 | 330 | 331 | } 332 | 333 | 334 | #endif 335 | -------------------------------------------------------------------------------- /picojson.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2010 Cybozu Labs, Inc. 3 | * Copyright 2011-2014 Kazuho Oku 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | * POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #ifndef picojson_h 29 | #define picojson_h 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | // for isnan/isinf 45 | #if __cplusplus>=201103L 46 | # include 47 | #else 48 | extern "C" { 49 | # ifdef _MSC_VER 50 | # include 51 | # elif defined(__INTEL_COMPILER) 52 | # include 53 | # else 54 | # include 55 | # endif 56 | } 57 | #endif 58 | 59 | #ifndef PICOJSON_USE_RVALUE_REFERENCE 60 | # if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600) 61 | # define PICOJSON_USE_RVALUE_REFERENCE 1 62 | # else 63 | # define PICOJSON_USE_RVALUE_REFERENCE 0 64 | # endif 65 | #endif//PICOJSON_USE_RVALUE_REFERENCE 66 | 67 | 68 | // experimental support for int64_t (see README.mkdn for detail) 69 | #ifdef PICOJSON_USE_INT64 70 | # define __STDC_FORMAT_MACROS 71 | # include 72 | # include 73 | #endif 74 | 75 | // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 76 | #ifndef PICOJSON_USE_LOCALE 77 | # define PICOJSON_USE_LOCALE 1 78 | #endif 79 | #if PICOJSON_USE_LOCALE 80 | extern "C" { 81 | # include 82 | } 83 | #endif 84 | 85 | #ifndef PICOJSON_ASSERT 86 | # define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0) 87 | #endif 88 | 89 | #ifdef _MSC_VER 90 | #define SNPRINTF _snprintf_s 91 | #pragma warning(push) 92 | #pragma warning(disable : 4244) // conversion from int to char 93 | #pragma warning(disable : 4127) // conditional expression is constant 94 | #pragma warning(disable : 4702) // unreachable code 95 | #else 96 | #define SNPRINTF snprintf 97 | #endif 98 | 99 | namespace picojson { 100 | 101 | enum { 102 | null_type, 103 | boolean_type, 104 | number_type, 105 | string_type, 106 | array_type, 107 | object_type 108 | #ifdef PICOJSON_USE_INT64 109 | , int64_type 110 | #endif 111 | }; 112 | 113 | enum { 114 | INDENT_WIDTH = 2 115 | }; 116 | 117 | struct null {}; 118 | 119 | class value { 120 | public: 121 | typedef std::vector array; 122 | typedef std::map object; 123 | union _storage { 124 | bool boolean_; 125 | double number_; 126 | #ifdef PICOJSON_USE_INT64 127 | int64_t int64_; 128 | #endif 129 | std::string* string_; 130 | array* array_; 131 | object* object_; 132 | }; 133 | protected: 134 | int type_; 135 | _storage u_; 136 | public: 137 | value(); 138 | value(int type, bool); 139 | explicit value(bool b); 140 | #ifdef PICOJSON_USE_INT64 141 | explicit value(int64_t i); 142 | #endif 143 | explicit value(double n); 144 | explicit value(const std::string& s); 145 | explicit value(const array& a); 146 | explicit value(const object& o); 147 | explicit value(const char* s); 148 | value(const char* s, size_t len); 149 | ~value(); 150 | value(const value& x); 151 | value& operator=(const value& x); 152 | #if PICOJSON_USE_RVALUE_REFERENCE 153 | value(value&& x)throw(); 154 | value& operator=(value&& x)throw(); 155 | #endif 156 | void swap(value& x)throw(); 157 | template bool is() const; 158 | template const T& get() const; 159 | template T& get(); 160 | bool evaluate_as_boolean() const; 161 | const value& get(size_t idx) const; 162 | const value& get(const std::string& key) const; 163 | value& get(size_t idx); 164 | value& get(const std::string& key); 165 | 166 | bool contains(size_t idx) const; 167 | bool contains(const std::string& key) const; 168 | std::string to_str() const; 169 | template void serialize(Iter os, bool prettify = false) const; 170 | std::string serialize(bool prettify = false) const; 171 | private: 172 | template value(const T*); // intentionally defined to block implicit conversion of pointer to bool 173 | template static void _indent(Iter os, int indent); 174 | template void _serialize(Iter os, int indent) const; 175 | std::string _serialize(int indent) const; 176 | }; 177 | 178 | typedef value::array array; 179 | typedef value::object object; 180 | 181 | inline value::value() : type_(null_type) {} 182 | 183 | inline value::value(int type, bool) : type_(type) { 184 | switch (type) { 185 | #define INIT(p, v) case p##type: u_.p = v; break 186 | INIT(boolean_, false); 187 | INIT(number_, 0.0); 188 | #ifdef PICOJSON_USE_INT64 189 | INIT(int64_, 0); 190 | #endif 191 | INIT(string_, new std::string()); 192 | INIT(array_, new array()); 193 | INIT(object_, new object()); 194 | #undef INIT 195 | default: break; 196 | } 197 | } 198 | 199 | inline value::value(bool b) : type_(boolean_type) { 200 | u_.boolean_ = b; 201 | } 202 | 203 | #ifdef PICOJSON_USE_INT64 204 | inline value::value(int64_t i) : type_(int64_type) { 205 | u_.int64_ = i; 206 | } 207 | #endif 208 | 209 | inline value::value(double n) : type_(number_type) { 210 | if ( 211 | #ifdef _MSC_VER 212 | ! _finite(n) 213 | #elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf)) 214 | std::isnan(n) || std::isinf(n) 215 | #else 216 | isnan(n) || isinf(n) 217 | #endif 218 | ) { 219 | throw std::overflow_error(""); 220 | } 221 | u_.number_ = n; 222 | } 223 | 224 | inline value::value(const std::string& s) : type_(string_type) { 225 | u_.string_ = new std::string(s); 226 | } 227 | 228 | inline value::value(const array& a) : type_(array_type) { 229 | u_.array_ = new array(a); 230 | } 231 | 232 | inline value::value(const object& o) : type_(object_type) { 233 | u_.object_ = new object(o); 234 | } 235 | 236 | inline value::value(const char* s) : type_(string_type) { 237 | u_.string_ = new std::string(s); 238 | } 239 | 240 | inline value::value(const char* s, size_t len) : type_(string_type) { 241 | u_.string_ = new std::string(s, len); 242 | } 243 | 244 | inline value::~value() { 245 | switch (type_) { 246 | #define DEINIT(p) case p##type: delete u_.p; break 247 | DEINIT(string_); 248 | DEINIT(array_); 249 | DEINIT(object_); 250 | #undef DEINIT 251 | default: break; 252 | } 253 | } 254 | 255 | inline value::value(const value& x) : type_(x.type_) { 256 | switch (type_) { 257 | #define INIT(p, v) case p##type: u_.p = v; break 258 | INIT(string_, new std::string(*x.u_.string_)); 259 | INIT(array_, new array(*x.u_.array_)); 260 | INIT(object_, new object(*x.u_.object_)); 261 | #undef INIT 262 | default: 263 | u_ = x.u_; 264 | break; 265 | } 266 | } 267 | 268 | inline value& value::operator=(const value& x) { 269 | if (this != &x) { 270 | value t(x); 271 | swap(t); 272 | } 273 | return *this; 274 | } 275 | 276 | #if PICOJSON_USE_RVALUE_REFERENCE 277 | inline value::value(value&& x)throw() : type_(null_type) { 278 | swap(x); 279 | } 280 | inline value& value::operator=(value&& x)throw() { 281 | swap(x); 282 | return *this; 283 | } 284 | #endif 285 | inline void value::swap(value& x)throw() { 286 | std::swap(type_, x.type_); 287 | std::swap(u_, x.u_); 288 | } 289 | 290 | #define IS(ctype, jtype) \ 291 | template <> inline bool value::is() const { \ 292 | return type_ == jtype##_type; \ 293 | } 294 | IS(null, null) 295 | IS(bool, boolean) 296 | #ifdef PICOJSON_USE_INT64 297 | IS(int64_t, int64) 298 | #endif 299 | IS(std::string, string) 300 | IS(array, array) 301 | IS(object, object) 302 | #undef IS 303 | template <> inline bool value::is() const { 304 | return type_ == number_type 305 | #ifdef PICOJSON_USE_INT64 306 | || type_ == int64_type 307 | #endif 308 | ; 309 | } 310 | 311 | #define GET(ctype, var) \ 312 | template <> inline const ctype& value::get() const { \ 313 | PICOJSON_ASSERT("type mismatch! call is() before get()" \ 314 | && is()); \ 315 | return var; \ 316 | } \ 317 | template <> inline ctype& value::get() { \ 318 | PICOJSON_ASSERT("type mismatch! call is() before get()" \ 319 | && is()); \ 320 | return var; \ 321 | } 322 | GET(bool, u_.boolean_) 323 | GET(std::string, *u_.string_) 324 | GET(array, *u_.array_) 325 | GET(object, *u_.object_) 326 | #ifdef PICOJSON_USE_INT64 327 | GET(double, (type_ == int64_type && (const_cast(this)->type_ = number_type, const_cast(this)->u_.number_ = u_.int64_), u_.number_)) 328 | GET(int64_t, u_.int64_) 329 | #else 330 | GET(double, u_.number_) 331 | #endif 332 | #undef GET 333 | 334 | inline bool value::evaluate_as_boolean() const { 335 | switch (type_) { 336 | case null_type: 337 | return false; 338 | case boolean_type: 339 | return u_.boolean_; 340 | case number_type: 341 | return u_.number_ != 0; 342 | #ifdef PICOJSON_USE_INT64 343 | case int64_type: 344 | return u_.int64_ != 0; 345 | #endif 346 | case string_type: 347 | return ! u_.string_->empty(); 348 | default: 349 | return true; 350 | } 351 | } 352 | 353 | inline const value& value::get(size_t idx) const { 354 | static value s_null; 355 | PICOJSON_ASSERT(is()); 356 | return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; 357 | } 358 | 359 | inline value& value::get(size_t idx) { 360 | static value s_null; 361 | PICOJSON_ASSERT(is()); 362 | return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; 363 | } 364 | 365 | inline const value& value::get(const std::string& key) const { 366 | static value s_null; 367 | PICOJSON_ASSERT(is()); 368 | object::const_iterator i = u_.object_->find(key); 369 | return i != u_.object_->end() ? i->second : s_null; 370 | } 371 | 372 | inline value& value::get(const std::string& key) { 373 | static value s_null; 374 | PICOJSON_ASSERT(is()); 375 | object::iterator i = u_.object_->find(key); 376 | return i != u_.object_->end() ? i->second : s_null; 377 | } 378 | 379 | inline bool value::contains(size_t idx) const { 380 | PICOJSON_ASSERT(is()); 381 | return idx < u_.array_->size(); 382 | } 383 | 384 | inline bool value::contains(const std::string& key) const { 385 | PICOJSON_ASSERT(is()); 386 | object::const_iterator i = u_.object_->find(key); 387 | return i != u_.object_->end(); 388 | } 389 | 390 | inline std::string value::to_str() const { 391 | switch (type_) { 392 | case null_type: return "null"; 393 | case boolean_type: return u_.boolean_ ? "true" : "false"; 394 | #ifdef PICOJSON_USE_INT64 395 | case int64_type: { 396 | char buf[sizeof("-9223372036854775808")]; 397 | SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_); 398 | return buf; 399 | } 400 | #endif 401 | case number_type: { 402 | char buf[256]; 403 | double tmp; 404 | SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); 405 | #if PICOJSON_USE_LOCALE 406 | char *decimal_point = localeconv()->decimal_point; 407 | if (strcmp(decimal_point, ".") != 0) { 408 | size_t decimal_point_len = strlen(decimal_point); 409 | for (char *p = buf; *p != '\0'; ++p) { 410 | if (strncmp(p, decimal_point, decimal_point_len) == 0) { 411 | return std::string(buf, p) + "." + (p + decimal_point_len); 412 | } 413 | } 414 | } 415 | #endif 416 | return buf; 417 | } 418 | case string_type: return *u_.string_; 419 | case array_type: return "array"; 420 | case object_type: return "object"; 421 | default: PICOJSON_ASSERT(0); 422 | #ifdef _MSC_VER 423 | __assume(0); 424 | #endif 425 | } 426 | return std::string(); 427 | } 428 | 429 | template void copy(const std::string& s, Iter oi) { 430 | std::copy(s.begin(), s.end(), oi); 431 | } 432 | 433 | template void serialize_str(const std::string& s, Iter oi) { 434 | *oi++ = '"'; 435 | for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { 436 | switch (*i) { 437 | #define MAP(val, sym) case val: copy(sym, oi); break 438 | MAP('"', "\\\""); 439 | MAP('\\', "\\\\"); 440 | MAP('/', "\\/"); 441 | MAP('\b', "\\b"); 442 | MAP('\f', "\\f"); 443 | MAP('\n', "\\n"); 444 | MAP('\r', "\\r"); 445 | MAP('\t', "\\t"); 446 | #undef MAP 447 | default: 448 | if (static_cast(*i) < 0x20 || *i == 0x7f) { 449 | char buf[7]; 450 | SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); 451 | copy(buf, buf + 6, oi); 452 | } else { 453 | *oi++ = *i; 454 | } 455 | break; 456 | } 457 | } 458 | *oi++ = '"'; 459 | } 460 | 461 | template void value::serialize(Iter oi, bool prettify) const { 462 | return _serialize(oi, prettify ? 0 : -1); 463 | } 464 | 465 | inline std::string value::serialize(bool prettify) const { 466 | return _serialize(prettify ? 0 : -1); 467 | } 468 | 469 | template void value::_indent(Iter oi, int indent) { 470 | *oi++ = '\n'; 471 | for (int i = 0; i < indent * INDENT_WIDTH; ++i) { 472 | *oi++ = ' '; 473 | } 474 | } 475 | 476 | template void value::_serialize(Iter oi, int indent) const { 477 | switch (type_) { 478 | case string_type: 479 | serialize_str(*u_.string_, oi); 480 | break; 481 | case array_type: { 482 | *oi++ = '['; 483 | if (indent != -1) { 484 | ++indent; 485 | } 486 | for (array::const_iterator i = u_.array_->begin(); 487 | i != u_.array_->end(); 488 | ++i) { 489 | if (i != u_.array_->begin()) { 490 | *oi++ = ','; 491 | } 492 | if (indent != -1) { 493 | _indent(oi, indent); 494 | } 495 | i->_serialize(oi, indent); 496 | } 497 | if (indent != -1) { 498 | --indent; 499 | if (! u_.array_->empty()) { 500 | _indent(oi, indent); 501 | } 502 | } 503 | *oi++ = ']'; 504 | break; 505 | } 506 | case object_type: { 507 | *oi++ = '{'; 508 | if (indent != -1) { 509 | ++indent; 510 | } 511 | for (object::const_iterator i = u_.object_->begin(); 512 | i != u_.object_->end(); 513 | ++i) { 514 | if (i != u_.object_->begin()) { 515 | *oi++ = ','; 516 | } 517 | if (indent != -1) { 518 | _indent(oi, indent); 519 | } 520 | serialize_str(i->first, oi); 521 | *oi++ = ':'; 522 | if (indent != -1) { 523 | *oi++ = ' '; 524 | } 525 | i->second._serialize(oi, indent); 526 | } 527 | if (indent != -1) { 528 | --indent; 529 | if (! u_.object_->empty()) { 530 | _indent(oi, indent); 531 | } 532 | } 533 | *oi++ = '}'; 534 | break; 535 | } 536 | default: 537 | copy(to_str(), oi); 538 | break; 539 | } 540 | if (indent == 0) { 541 | *oi++ = '\n'; 542 | } 543 | } 544 | 545 | inline std::string value::_serialize(int indent) const { 546 | std::string s; 547 | _serialize(std::back_inserter(s), indent); 548 | return s; 549 | } 550 | 551 | template class input { 552 | protected: 553 | Iter cur_, end_; 554 | int last_ch_; 555 | bool ungot_; 556 | int line_; 557 | public: 558 | input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} 559 | int getc() { 560 | if (ungot_) { 561 | ungot_ = false; 562 | return last_ch_; 563 | } 564 | if (cur_ == end_) { 565 | last_ch_ = -1; 566 | return -1; 567 | } 568 | if (last_ch_ == '\n') { 569 | line_++; 570 | } 571 | last_ch_ = *cur_ & 0xff; 572 | ++cur_; 573 | return last_ch_; 574 | } 575 | void ungetc() { 576 | if (last_ch_ != -1) { 577 | PICOJSON_ASSERT(! ungot_); 578 | ungot_ = true; 579 | } 580 | } 581 | Iter cur() const { return cur_; } 582 | int line() const { return line_; } 583 | void skip_ws() { 584 | while (1) { 585 | int ch = getc(); 586 | if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { 587 | ungetc(); 588 | break; 589 | } 590 | } 591 | } 592 | bool expect(int expect) { 593 | skip_ws(); 594 | if (getc() != expect) { 595 | ungetc(); 596 | return false; 597 | } 598 | return true; 599 | } 600 | bool match(const std::string& pattern) { 601 | for (std::string::const_iterator pi(pattern.begin()); 602 | pi != pattern.end(); 603 | ++pi) { 604 | if (getc() != *pi) { 605 | ungetc(); 606 | return false; 607 | } 608 | } 609 | return true; 610 | } 611 | }; 612 | 613 | template inline int _parse_quadhex(input &in) { 614 | int uni_ch = 0, hex; 615 | for (int i = 0; i < 4; i++) { 616 | if ((hex = in.getc()) == -1) { 617 | return -1; 618 | } 619 | if ('0' <= hex && hex <= '9') { 620 | hex -= '0'; 621 | } else if ('A' <= hex && hex <= 'F') { 622 | hex -= 'A' - 0xa; 623 | } else if ('a' <= hex && hex <= 'f') { 624 | hex -= 'a' - 0xa; 625 | } else { 626 | in.ungetc(); 627 | return -1; 628 | } 629 | uni_ch = uni_ch * 16 + hex; 630 | } 631 | return uni_ch; 632 | } 633 | 634 | template inline bool _parse_codepoint(String& out, input& in) { 635 | int uni_ch; 636 | if ((uni_ch = _parse_quadhex(in)) == -1) { 637 | return false; 638 | } 639 | if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { 640 | if (0xdc00 <= uni_ch) { 641 | // a second 16-bit of a surrogate pair appeared 642 | return false; 643 | } 644 | // first 16-bit of surrogate pair, get the next one 645 | if (in.getc() != '\\' || in.getc() != 'u') { 646 | in.ungetc(); 647 | return false; 648 | } 649 | int second = _parse_quadhex(in); 650 | if (! (0xdc00 <= second && second <= 0xdfff)) { 651 | return false; 652 | } 653 | uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); 654 | uni_ch += 0x10000; 655 | } 656 | if (uni_ch < 0x80) { 657 | out.push_back(uni_ch); 658 | } else { 659 | if (uni_ch < 0x800) { 660 | out.push_back(0xc0 | (uni_ch >> 6)); 661 | } else { 662 | if (uni_ch < 0x10000) { 663 | out.push_back(0xe0 | (uni_ch >> 12)); 664 | } else { 665 | out.push_back(0xf0 | (uni_ch >> 18)); 666 | out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); 667 | } 668 | out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); 669 | } 670 | out.push_back(0x80 | (uni_ch & 0x3f)); 671 | } 672 | return true; 673 | } 674 | 675 | template inline bool _parse_string(String& out, input& in) { 676 | while (1) { 677 | int ch = in.getc(); 678 | if (ch < ' ') { 679 | in.ungetc(); 680 | return false; 681 | } else if (ch == '"') { 682 | return true; 683 | } else if (ch == '\\') { 684 | if ((ch = in.getc()) == -1) { 685 | return false; 686 | } 687 | switch (ch) { 688 | #define MAP(sym, val) case sym: out.push_back(val); break 689 | MAP('"', '\"'); 690 | MAP('\\', '\\'); 691 | MAP('/', '/'); 692 | MAP('b', '\b'); 693 | MAP('f', '\f'); 694 | MAP('n', '\n'); 695 | MAP('r', '\r'); 696 | MAP('t', '\t'); 697 | #undef MAP 698 | case 'u': 699 | if (! _parse_codepoint(out, in)) { 700 | return false; 701 | } 702 | break; 703 | default: 704 | return false; 705 | } 706 | } else { 707 | out.push_back(ch); 708 | } 709 | } 710 | return false; 711 | } 712 | 713 | template inline bool _parse_array(Context& ctx, input& in) { 714 | if (! ctx.parse_array_start()) { 715 | return false; 716 | } 717 | size_t idx = 0; 718 | if (in.expect(']')) { 719 | return ctx.parse_array_stop(idx); 720 | } 721 | do { 722 | if (! ctx.parse_array_item(in, idx)) { 723 | return false; 724 | } 725 | idx++; 726 | } while (in.expect(',')); 727 | return in.expect(']') && ctx.parse_array_stop(idx); 728 | } 729 | 730 | template inline bool _parse_object(Context& ctx, input& in) { 731 | if (! ctx.parse_object_start()) { 732 | return false; 733 | } 734 | if (in.expect('}')) { 735 | return true; 736 | } 737 | do { 738 | std::string key; 739 | if (! in.expect('"') 740 | || ! _parse_string(key, in) 741 | || ! in.expect(':')) { 742 | return false; 743 | } 744 | if (! ctx.parse_object_item(in, key)) { 745 | return false; 746 | } 747 | } while (in.expect(',')); 748 | return in.expect('}'); 749 | } 750 | 751 | template inline std::string _parse_number(input& in) { 752 | std::string num_str; 753 | while (1) { 754 | int ch = in.getc(); 755 | if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' 756 | || ch == 'e' || ch == 'E') { 757 | num_str.push_back(ch); 758 | } else if (ch == '.') { 759 | #if PICOJSON_USE_LOCALE 760 | num_str += localeconv()->decimal_point; 761 | #else 762 | num_str.push_back('.'); 763 | #endif 764 | } else { 765 | in.ungetc(); 766 | break; 767 | } 768 | } 769 | return num_str; 770 | } 771 | 772 | template inline bool _parse(Context& ctx, input& in) { 773 | in.skip_ws(); 774 | int ch = in.getc(); 775 | switch (ch) { 776 | #define IS(ch, text, op) case ch: \ 777 | if (in.match(text) && op) { \ 778 | return true; \ 779 | } else { \ 780 | return false; \ 781 | } 782 | IS('n', "ull", ctx.set_null()); 783 | IS('f', "alse", ctx.set_bool(false)); 784 | IS('t', "rue", ctx.set_bool(true)); 785 | #undef IS 786 | case '"': 787 | return ctx.parse_string(in); 788 | case '[': 789 | return _parse_array(ctx, in); 790 | case '{': 791 | return _parse_object(ctx, in); 792 | default: 793 | if (('0' <= ch && ch <= '9') || ch == '-') { 794 | double f; 795 | char *endp; 796 | in.ungetc(); 797 | std::string num_str = _parse_number(in); 798 | if (num_str.empty()) { 799 | return false; 800 | } 801 | #ifdef PICOJSON_USE_INT64 802 | { 803 | errno = 0; 804 | intmax_t ival = strtoimax(num_str.c_str(), &endp, 10); 805 | if (errno == 0 806 | && std::numeric_limits::min() <= ival 807 | && ival <= std::numeric_limits::max() 808 | && endp == num_str.c_str() + num_str.size()) { 809 | ctx.set_int64(ival); 810 | return true; 811 | } 812 | } 813 | #endif 814 | f = strtod(num_str.c_str(), &endp); 815 | if (endp == num_str.c_str() + num_str.size()) { 816 | ctx.set_number(f); 817 | return true; 818 | } 819 | return false; 820 | } 821 | break; 822 | } 823 | in.ungetc(); 824 | return false; 825 | } 826 | 827 | class deny_parse_context { 828 | public: 829 | bool set_null() { return false; } 830 | bool set_bool(bool) { return false; } 831 | #ifdef PICOJSON_USE_INT64 832 | bool set_int64(int64_t) { return false; } 833 | #endif 834 | bool set_number(double) { return false; } 835 | template bool parse_string(input&) { return false; } 836 | bool parse_array_start() { return false; } 837 | template bool parse_array_item(input&, size_t) { 838 | return false; 839 | } 840 | bool parse_array_stop(size_t) { return false; } 841 | bool parse_object_start() { return false; } 842 | template bool parse_object_item(input&, const std::string&) { 843 | return false; 844 | } 845 | }; 846 | 847 | class default_parse_context { 848 | protected: 849 | value* out_; 850 | public: 851 | default_parse_context(value* out) : out_(out) {} 852 | bool set_null() { 853 | *out_ = value(); 854 | return true; 855 | } 856 | bool set_bool(bool b) { 857 | *out_ = value(b); 858 | return true; 859 | } 860 | #ifdef PICOJSON_USE_INT64 861 | bool set_int64(int64_t i) { 862 | *out_ = value(i); 863 | return true; 864 | } 865 | #endif 866 | bool set_number(double f) { 867 | *out_ = value(f); 868 | return true; 869 | } 870 | template bool parse_string(input& in) { 871 | *out_ = value(string_type, false); 872 | return _parse_string(out_->get(), in); 873 | } 874 | bool parse_array_start() { 875 | *out_ = value(array_type, false); 876 | return true; 877 | } 878 | template bool parse_array_item(input& in, size_t) { 879 | array& a = out_->get(); 880 | a.push_back(value()); 881 | default_parse_context ctx(&a.back()); 882 | return _parse(ctx, in); 883 | } 884 | bool parse_array_stop(size_t) { return true; } 885 | bool parse_object_start() { 886 | *out_ = value(object_type, false); 887 | return true; 888 | } 889 | template bool parse_object_item(input& in, const std::string& key) { 890 | object& o = out_->get(); 891 | default_parse_context ctx(&o[key]); 892 | return _parse(ctx, in); 893 | } 894 | private: 895 | default_parse_context(const default_parse_context&); 896 | default_parse_context& operator=(const default_parse_context&); 897 | }; 898 | 899 | class null_parse_context { 900 | public: 901 | struct dummy_str { 902 | void push_back(int) {} 903 | }; 904 | public: 905 | null_parse_context() {} 906 | bool set_null() { return true; } 907 | bool set_bool(bool) { return true; } 908 | #ifdef PICOJSON_USE_INT64 909 | bool set_int64(int64_t) { return true; } 910 | #endif 911 | bool set_number(double) { return true; } 912 | template bool parse_string(input& in) { 913 | dummy_str s; 914 | return _parse_string(s, in); 915 | } 916 | bool parse_array_start() { return true; } 917 | template bool parse_array_item(input& in, size_t) { 918 | return _parse(*this, in); 919 | } 920 | bool parse_array_stop(size_t) { return true; } 921 | bool parse_object_start() { return true; } 922 | template bool parse_object_item(input& in, const std::string&) { 923 | return _parse(*this, in); 924 | } 925 | private: 926 | null_parse_context(const null_parse_context&); 927 | null_parse_context& operator=(const null_parse_context&); 928 | }; 929 | 930 | // obsolete, use the version below 931 | template inline std::string parse(value& out, Iter& pos, const Iter& last) { 932 | std::string err; 933 | pos = parse(out, pos, last, &err); 934 | return err; 935 | } 936 | 937 | template inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { 938 | input in(first, last); 939 | if (! _parse(ctx, in) && err != NULL) { 940 | char buf[64]; 941 | SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); 942 | *err = buf; 943 | while (1) { 944 | int ch = in.getc(); 945 | if (ch == -1 || ch == '\n') { 946 | break; 947 | } else if (ch >= ' ') { 948 | err->push_back(ch); 949 | } 950 | } 951 | } 952 | return in.cur(); 953 | } 954 | 955 | template inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { 956 | default_parse_context ctx(&out); 957 | return _parse(ctx, first, last, err); 958 | } 959 | 960 | inline std::string parse(value& out, const std::string& s) { 961 | std::string err; 962 | parse(out, s.begin(), s.end(), &err); 963 | return err; 964 | } 965 | 966 | inline std::string parse(value& out, std::istream& is) { 967 | std::string err; 968 | parse(out, std::istreambuf_iterator(is.rdbuf()), 969 | std::istreambuf_iterator(), &err); 970 | return err; 971 | } 972 | 973 | template struct last_error_t { 974 | static std::string s; 975 | }; 976 | template std::string last_error_t::s; 977 | 978 | inline void set_last_error(const std::string& s) { 979 | last_error_t::s = s; 980 | } 981 | 982 | inline const std::string& get_last_error() { 983 | return last_error_t::s; 984 | } 985 | 986 | inline bool operator==(const value& x, const value& y) { 987 | if (x.is()) 988 | return y.is(); 989 | #define PICOJSON_CMP(type) \ 990 | if (x.is()) \ 991 | return y.is() && x.get() == y.get() 992 | PICOJSON_CMP(bool); 993 | PICOJSON_CMP(double); 994 | PICOJSON_CMP(std::string); 995 | PICOJSON_CMP(array); 996 | PICOJSON_CMP(object); 997 | #undef PICOJSON_CMP 998 | PICOJSON_ASSERT(0); 999 | #ifdef _MSC_VER 1000 | __assume(0); 1001 | #endif 1002 | return false; 1003 | } 1004 | 1005 | inline bool operator!=(const value& x, const value& y) { 1006 | return ! (x == y); 1007 | } 1008 | } 1009 | 1010 | #if !PICOJSON_USE_RVALUE_REFERENCE 1011 | namespace std { 1012 | template<> inline void swap(picojson::value& x, picojson::value& y) 1013 | { 1014 | x.swap(y); 1015 | } 1016 | } 1017 | #endif 1018 | 1019 | inline std::istream& operator>>(std::istream& is, picojson::value& x) 1020 | { 1021 | picojson::set_last_error(std::string()); 1022 | std::string err = picojson::parse(x, is); 1023 | if (! err.empty()) { 1024 | picojson::set_last_error(err); 1025 | is.setstate(std::ios::failbit); 1026 | } 1027 | return is; 1028 | } 1029 | 1030 | inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) 1031 | { 1032 | x.serialize(std::ostream_iterator(os)); 1033 | return os; 1034 | } 1035 | #ifdef _MSC_VER 1036 | #pragma warning(pop) 1037 | #endif 1038 | 1039 | #endif 1040 | -------------------------------------------------------------------------------- /pmt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_PMT_HPP_ 2 | #define _TSD_PMT_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include "util.hpp" 8 | #include "descriptor.hpp" 9 | 10 | namespace tsd 11 | { 12 | struct program_element 13 | { 14 | uint8_t stream_type; 15 | uint16_t elementary_pid; 16 | std::vector es_info; 17 | 18 | void unpack(const uint8_t** pp, const uint8_t* pend) { 19 | const uint8_t* p = *pp; 20 | if(pend - p < 5) 21 | std::runtime_error(""); 22 | 23 | stream_type = get8(p); 24 | p += 1; 25 | elementary_pid = get16(p) & 0x1FFF; 26 | p += 2; 27 | int32_t es_info_length = get16(p) & 0x0FFF; 28 | p += 2; 29 | const uint8_t* peiend = p + es_info_length; 30 | es_info.clear(); 31 | while(peiend - p >= 2) { 32 | es_info.resize(es_info.size()+1); 33 | es_info.back().unpack(&p, pend); 34 | } 35 | p = peiend; 36 | *pp = p; 37 | } 38 | }; 39 | 40 | struct program_map_table 41 | { 42 | uint16_t pcr_pid; 43 | std::vector program_info; 44 | std::vector program_elements; 45 | 46 | public: 47 | void unpack(const char* data, size_t size) { 48 | const uint8_t* p = reinterpret_cast(data); 49 | const uint8_t* pend = p+size; 50 | 51 | pcr_pid = get16(p) & 0x1FFF; 52 | p += 2; 53 | int32_t program_info_length = get16(p) & 0x0FFF; 54 | p += 2; 55 | const uint8_t* piend = p + program_info_length; 56 | program_info.clear(); 57 | while(piend - p >= 2) { 58 | program_info.resize(program_info.size()+1); 59 | program_info.back().unpack(&p, pend); 60 | } 61 | p = piend; 62 | 63 | program_elements.clear(); 64 | while(pend - p >= 5+4) { 65 | program_elements.resize(program_elements.size()+1); 66 | program_elements.back().unpack(&p, pend); 67 | } 68 | } 69 | 70 | }; 71 | 72 | } 73 | 74 | 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /sdt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SDT_HPP_ 2 | #define _TSD_SDT_HPP_ 3 | 4 | #include "util.hpp" 5 | #include "descriptor.hpp" 6 | 7 | namespace tsd 8 | { 9 | 10 | 11 | struct service_description_table 12 | { 13 | struct service 14 | { 15 | uint16_t service_id; 16 | std::vector descriptors; 17 | }; 18 | 19 | // Table ID 0x42 (self stream) 0x46 (other stream) 20 | uint16_t original_network_id; 21 | std::vector services; 22 | 23 | void unpack(const char* data, size_t size) { 24 | const uint8_t* p = reinterpret_cast(data); 25 | const uint8_t* pend = p+size; 26 | 27 | services.clear(); 28 | 29 | original_network_id = get16(p); 30 | p += 3; 31 | 32 | while(pend - p > 4) { 33 | services.resize(services.size()+1); 34 | auto& s = services.back(); 35 | 36 | s.service_id = get16(p); 37 | p += 3; 38 | size_t loop_length = get16(p) & 0x0FFF; 39 | p += 2; 40 | const uint8_t* ploop_end = p + loop_length; 41 | if(pend - p - 4 < loop_length) 42 | std::runtime_error(""); 43 | 44 | while(p < ploop_end) { 45 | s.descriptors.resize(s.descriptors.size()+1); 46 | s.descriptors.back().unpack(&p, ploop_end); 47 | } 48 | } 49 | } 50 | }; 51 | 52 | } 53 | 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /section.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SECTION_HPP_ 2 | #define _TSD_SECTION_HPP_ 3 | 4 | #include "section_header.hpp" 5 | 6 | namespace tsd 7 | { 8 | class section 9 | { 10 | public: 11 | section_header header; 12 | const char* payload; 13 | 14 | public: 15 | void unpack(const char* data, size_t size) { 16 | const uint8_t* p = reinterpret_cast(data); 17 | unpack(&p, p+size); 18 | } 19 | 20 | void unpack( 21 | const uint8_t** pp, 22 | const uint8_t* pend) { 23 | const uint8_t* p = *pp; 24 | 25 | header.unpack(&p, pend); 26 | payload = reinterpret_cast(p); 27 | 28 | *pp = p; 29 | } 30 | 31 | template 32 | std::unique_ptr as() const { 33 | std::unique_ptr d(new T); 34 | convert(*d); 35 | return std::move(d); 36 | } 37 | 38 | template 39 | void convert(T& t) const { 40 | t.unpack(payload, header.get_payload_length()); 41 | } 42 | 43 | 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /section_header.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SECTION_HEADER_HPP_ 2 | #define _TSD_SECTION_HEADER_HPP_ 3 | 4 | #include 5 | #include "util.hpp" 6 | 7 | namespace tsd 8 | { 9 | 10 | class section_header 11 | { 12 | public: 13 | uint8_t table_id; 14 | uint8_t section_syntax_indicator; 15 | uint16_t section_length; 16 | uint16_t table_id_extension; 17 | uint8_t version; 18 | uint8_t current_next_indicator; 19 | uint8_t section_number; 20 | uint8_t last_section_number; 21 | 22 | public: 23 | void unpack( 24 | const uint8_t** pp, 25 | const uint8_t* pend) { 26 | const uint8_t* p = *pp; 27 | 28 | if(pend - p < 3) 29 | throw std::runtime_error(""); 30 | 31 | table_id = get8(p); 32 | p += 1; 33 | section_syntax_indicator = get8(p) >> 7; 34 | section_length = get16(p) & 0x0FFF; 35 | p += 2; 36 | if(section_syntax_indicator == 0) { 37 | *pp = p; 38 | return; 39 | } 40 | 41 | if(pend - p < 5) 42 | throw std::runtime_error(""); 43 | 44 | table_id_extension = get16(p); 45 | p += 2; 46 | version = (get8(p) >> 1) & 0x1F; 47 | current_next_indicator = get8(p) & 0x01; 48 | p += 1; 49 | section_number = get8(p); 50 | p += 1; 51 | last_section_number = get8(p); 52 | p += 1; 53 | 54 | *pp = p; 55 | } 56 | 57 | size_t get_payload_length() const { 58 | if(section_syntax_indicator) 59 | return section_length-5; 60 | else 61 | return section_length; 62 | } 63 | }; 64 | 65 | } 66 | 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /splitter_context.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_SPLITTER_CONTEXT_HPP_ 2 | #define _TSD_SPLITTER_CONTEXT_HPP_ 3 | 4 | #include "wrap_around_time_stamp.hpp" 5 | 6 | namespace tsd 7 | { 8 | class splitter_context 9 | { 10 | public: 11 | enum class state 12 | { 13 | init, 14 | buffering, 15 | writing 16 | }; 17 | 18 | public: 19 | splitter_context() : 20 | state_(state::init), 21 | trim_threshold_sec_(0) {} 22 | 23 | explicit splitter_context(int64_t trim_threshold_sec) : 24 | state_(state::init), 25 | trim_threshold_sec_(trim_threshold_sec) {} 26 | 27 | const state get_state() const { 28 | return state_; 29 | } 30 | 31 | void signal_pcr(uint64_t pcr) { 32 | switch(state_) { 33 | case state::init: 34 | { 35 | start_pcr_ = wrap_around_time_stamp(pcr); 36 | state_ = state::buffering; 37 | } 38 | break; 39 | case state::buffering: 40 | { 41 | wrap_around_time_stamp wpcr(pcr); 42 | if(wpcr < start_pcr_) 43 | return; 44 | 45 | if(pcr_to_sec(wpcr - start_pcr_) >= trim_threshold_sec_) { 46 | state_ = state::writing; 47 | } 48 | } 49 | break; 50 | case state::writing: 51 | { 52 | } 53 | break; 54 | } 55 | } 56 | 57 | void signal_split() { 58 | switch(state_) { 59 | case state::init: 60 | { 61 | } 62 | break; 63 | case state::buffering: 64 | { 65 | state_ = state::init; 66 | } 67 | break; 68 | case state::writing: 69 | { 70 | state_ = state::init; 71 | } 72 | break; 73 | } 74 | } 75 | private: 76 | int64_t pcr_to_sec(int64_t pcr) const { 77 | return pcr / 90000; 78 | } 79 | 80 | private: 81 | state state_; 82 | int64_t trim_threshold_sec_; 83 | wrap_around_time_stamp start_pcr_; 84 | }; 85 | 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /tot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_TOT_HPP_ 2 | #define _TSD_TOT_HPP_ 3 | 4 | #include 5 | #include "aribtime.hpp" 6 | #include "util.hpp" 7 | 8 | namespace tsd 9 | { 10 | using std::chrono::system_clock; 11 | 12 | // TDT: 0x70, TOT: 0x73 13 | struct time_offset_table 14 | { 15 | aribtime time; 16 | 17 | public: 18 | void unpack(const char* data, size_t size) { 19 | const uint8_t* p = reinterpret_cast(data); 20 | const uint8_t* pend = p+size; 21 | 22 | if(size < 5) 23 | std::runtime_error(""); 24 | 25 | time.unpack(&p, pend); 26 | } 27 | }; 28 | 29 | } 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /transport_packet.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_TRANSPORT_PACKET_HPP_ 2 | #define _TSD_TRANSPORT_PACKET_HPP_ 3 | 4 | #include 5 | #include "util.hpp" 6 | #include "packer.hpp" 7 | 8 | namespace tsd 9 | { 10 | 11 | class transport_packet 12 | { 13 | public: 14 | struct adaptation_field 15 | { 16 | uint8_t length; 17 | uint8_t header_block; 18 | uint64_t pcr_base; 19 | uint16_t pcr_extension; 20 | std::string other_data_block; // FIXME: not parse yet 21 | 22 | adaptation_field() : 23 | length(0) {} 24 | 25 | uint8_t discontinuity_indicator() const { 26 | return header_block & 0x80; 27 | } 28 | 29 | uint8_t random_access_indicator() const { 30 | return header_block & 0x40; 31 | } 32 | 33 | uint8_t elementary_stream_priority_indicator() const { 34 | return header_block & 0x20; 35 | } 36 | 37 | uint8_t pcr_flag() const { 38 | return header_block & 0x10; 39 | } 40 | 41 | uint8_t opcr_flag() const { 42 | return header_block & 0x08; 43 | } 44 | 45 | uint8_t splicing_point_flag() const { 46 | return header_block & 0x04; 47 | } 48 | 49 | uint8_t transport_private_data_flag() const { 50 | return header_block & 0x02; 51 | } 52 | 53 | uint8_t adaptation_field_extension_flag() const { 54 | return header_block & 0x01; 55 | } 56 | 57 | void unpack(const uint8_t** pp, const uint8_t* pend) { 58 | const uint8_t* p = *pp; 59 | 60 | if(pend - p < 1) 61 | std::runtime_error(""); 62 | 63 | length = get8(p); 64 | p += 1; 65 | 66 | if(length > 0) { 67 | const uint8_t* pafield_end = p + length; 68 | header_block = get8(p); 69 | p += 1; 70 | 71 | if(pcr_flag()) { 72 | pcr_base = get32(p); 73 | pcr_base <<= 1; 74 | pcr_base |= (get8(p+4) >> 7); 75 | p += 4; 76 | pcr_extension = ((get8(p) & 0x01) << 8) | get8(p+1); 77 | p += 2; 78 | } 79 | 80 | //FIXME: skip parsing other params 81 | other_data_block.assign( 82 | reinterpret_cast(p), 83 | pafield_end - p); 84 | 85 | p = pafield_end; 86 | } 87 | 88 | *pp = p; 89 | } 90 | 91 | void pack(std::ostream& ost) const { 92 | packer p(ost); 93 | p.pack8(length); 94 | if(length > 0) { 95 | p.pack8(header_block); 96 | 97 | if(pcr_flag()) { 98 | p.pack32(pcr_base >> 1); 99 | uint16_t pcr_block; 100 | pcr_block = (pcr_base & 0x01) << (16-1); 101 | pcr_block |= 0x3F << (16-1-6); 102 | pcr_block |= pcr_extension & 0x01FF; 103 | p.pack16(pcr_block); 104 | } 105 | 106 | //FIXME: packing remains 107 | p.pack_bytes( 108 | other_data_block.data(), 109 | other_data_block.size()); 110 | } 111 | } 112 | }; 113 | 114 | public: 115 | static constexpr uint8_t sync_byte = 0x47; 116 | static constexpr size_t size = 188; 117 | 118 | public: 119 | uint8_t transport_error_indicator; 120 | uint8_t payload_unit_start_indicator; 121 | uint8_t transport_priority; 122 | uint16_t pid; 123 | uint8_t transport_scrambling_control; 124 | uint8_t adaptation_field_control; 125 | uint8_t continuity_counter; 126 | adaptation_field afield; 127 | const char* payload; 128 | 129 | public: 130 | void unpack(const char* data, size_t size) { 131 | auto p = reinterpret_cast(data); 132 | unpack(&p, p+size); 133 | } 134 | 135 | void unpack(const uint8_t** pp, const uint8_t* pend) { 136 | auto p = *pp; 137 | if(get8(p) != sync_byte) 138 | std::runtime_error("syncbyte error"); 139 | p += 1; 140 | transport_error_indicator = (get8(p) & 0x80) >> 7; 141 | payload_unit_start_indicator = (get8(p) & 0x40) >> 6; 142 | transport_priority = (get8(p) & 0x20) >> 5; 143 | pid = get16(p) & 0x1FFF; 144 | p += 2; 145 | transport_scrambling_control = (get8(p) & 0x60) >> 6; 146 | adaptation_field_control = (get8(p) & 0x30) >> 4; 147 | continuity_counter = get8(p) & 0x0F; 148 | p += 1; 149 | if(has_adaptation_field()) { 150 | afield.unpack(&p, pend); 151 | } 152 | if(has_payload()) 153 | payload = reinterpret_cast(p); 154 | else 155 | payload = nullptr; 156 | 157 | *pp = p; 158 | } 159 | 160 | void pack(std::ostream& ost) const { 161 | packer p(ost); 162 | size_t packed_size; 163 | p.pack8(sync_byte); 164 | 165 | std::bitset<16> head1(pid); 166 | head1.set(15, transport_error_indicator); 167 | head1.set(14, payload_unit_start_indicator); 168 | head1.set(13, transport_priority); 169 | p.pack16(head1.to_ulong()); 170 | 171 | uint8_t head2; 172 | head2 = transport_scrambling_control << 6; 173 | head2 |= adaptation_field_control << 4; 174 | head2 |= continuity_counter; 175 | p.pack8(head2); 176 | packed_size = 4; 177 | if(has_adaptation_field()) { 178 | afield.pack(ost); 179 | packed_size += 1 + afield.length; 180 | } 181 | if(has_payload()) { 182 | p.pack_bytes(payload, payload_size()); 183 | packed_size += payload_size(); 184 | } 185 | p.pack_fill(transport_packet::size - packed_size, 0xFF); 186 | } 187 | 188 | size_t pointer_field() const { 189 | return *reinterpret_cast(payload); 190 | } 191 | size_t payload_size() const { 192 | if(has_adaptation_field()) 193 | return size - 5 - afield.length; 194 | else 195 | return size - 4; 196 | } 197 | 198 | bool has_payload() const { 199 | return adaptation_field_control & 0x01; 200 | } 201 | bool has_adaptation_field() const { 202 | return adaptation_field_control & 0x02; 203 | } 204 | }; 205 | 206 | 207 | } 208 | 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /ts_reader.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_TS_READER_HPP_ 2 | #define _TSD_TS_READER_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "util.hpp" 11 | #include "transport_packet.hpp" 12 | 13 | 14 | namespace tsd 15 | { 16 | class tsreader 17 | { 18 | std::array buffer_; 19 | public: 20 | static const size_t max_resync_size = 0xFFFF; 21 | 22 | public: 23 | tsreader(std::istream& input) : input_(input) {} 24 | 25 | bool next(transport_packet& result) { 26 | while(true) { 27 | input_.exceptions(std::istream::badbit); 28 | input_.read(buffer_.data(), buffer_.size()); 29 | if(!input_) 30 | return false; 31 | 32 | // check packet sync byte 33 | if(buffer_[0] != transport_packet::sync_byte) { 34 | input_.exceptions(std::istream::failbit | std::istream::badbit); 35 | auto pos = input_.tellg(); 36 | input_.seekg( 37 | -std::min(pos, transport_packet::size), 38 | std::ios_base::cur); 39 | if(!resync()) 40 | return false; 41 | } 42 | else { 43 | break; 44 | } 45 | } 46 | result.unpack(buffer_.data(), buffer_.size()); 47 | return true; 48 | } 49 | 50 | std::streampos tellg() { 51 | input_.exceptions(std::istream::failbit | std::istream::badbit); 52 | return input_.tellg(); 53 | } 54 | 55 | void seekg( 56 | std::streamoff off, 57 | std::ios_base::seekdir way) { 58 | input_.exceptions(std::istream::failbit | std::istream::badbit); 59 | input_.seekg(off, way); 60 | } 61 | 62 | private: 63 | bool resync() { 64 | char ch; 65 | const uint8_t* c = reinterpret_cast(&ch); 66 | size_t i; 67 | for(i = 0; i < max_resync_size; ++i) { 68 | input_.exceptions(std::istream::badbit); 69 | input_.get(ch); 70 | if(!input_) 71 | return false; 72 | if(*c == transport_packet::sync_byte) { 73 | input_.exceptions(std::istream::failbit | std::istream::badbit); 74 | input_.seekg(-1, std::ios_base::cur); 75 | return true; 76 | } 77 | } 78 | throw std::runtime_error("invalid data. cannot find 0x47 sync byte"); 79 | } 80 | 81 | private: 82 | std::istream& input_; 83 | }; 84 | 85 | } // namespace tsd 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /ts_trimmer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_TS_TRIMMER_HPP_ 2 | #define _TSD_TS_TRIMMER_HPP_ 3 | 4 | #include 5 | #include 6 | #include "splitter_context.hpp" 7 | #include "transport_packet.hpp" 8 | 9 | namespace tsd 10 | { 11 | 12 | class ts_trimmer 13 | { 14 | enum class state 15 | { 16 | buffering, 17 | writing, 18 | buffering2, 19 | eof 20 | }; 21 | public: 22 | ts_trimmer( 23 | std::ostream& ost, 24 | std::iostream& buffer, 25 | int64_t trim_threshold_sec, 26 | bool enable_pmt_separator, 27 | bool enable_eit_separator, 28 | int overlap_front, 29 | int overlap_back) : 30 | output_(ost), 31 | buffer_(buffer), 32 | input_pos_(0), 33 | context_(trim_threshold_sec), 34 | state_(state::buffering), 35 | enable_pmt_separator_(enable_pmt_separator), 36 | enable_eit_separator_(enable_eit_separator), 37 | overlap_front_(overlap_front), 38 | overlap_back_(overlap_back), 39 | written_overlap_back_(0) 40 | {} 41 | 42 | void add_packet(const transport_packet& packet) { 43 | switch(state_) { 44 | case state::buffering: 45 | { 46 | packet.pack(buffer_); 47 | } 48 | break; 49 | case state::writing: 50 | { 51 | packet.pack(output_); 52 | } 53 | break; 54 | case state::buffering2: 55 | { 56 | if(written_overlap_back_ < overlap_back_){ 57 | packet.pack(output_); 58 | written_overlap_back_ += 1; 59 | } 60 | else { 61 | packet.pack(buffer_); 62 | } 63 | } 64 | break; 65 | case state::eof: 66 | { 67 | } 68 | break; 69 | } 70 | } 71 | 72 | void signal_pmt() { 73 | if(enable_pmt_separator_) 74 | signal_split(); 75 | } 76 | 77 | void signal_eit() { 78 | if(enable_eit_separator_) 79 | signal_split(); 80 | } 81 | 82 | void signal_pcr(uint64_t pcr) { 83 | switch(state_) { 84 | case state::buffering: 85 | { 86 | context_.signal_pcr(pcr); 87 | if(context_.get_state() == 88 | splitter_context::state::writing) { 89 | flush_buffer(); 90 | state_ = state::writing; 91 | } 92 | } 93 | break; 94 | case state::writing: 95 | { 96 | context_.signal_pcr(pcr); 97 | } 98 | break; 99 | case state::buffering2: 100 | { 101 | context_.signal_pcr(pcr); 102 | if(context_.get_state() == 103 | splitter_context::state::writing){ 104 | flush_buffer(); 105 | written_overlap_back_ = 0; 106 | state_ = state::writing; 107 | } 108 | } 109 | break; 110 | case state::eof: 111 | { 112 | } 113 | break; 114 | } 115 | } 116 | 117 | void signal_finish_stream() { 118 | switch(state_) { 119 | case state::buffering: 120 | { 121 | drop_buffer(0); 122 | state_ = state::eof; 123 | } 124 | break; 125 | case state::writing: 126 | { 127 | state_ = state::eof; 128 | } 129 | break; 130 | case state::buffering2: 131 | { 132 | drop_buffer(0); 133 | state_ = state::eof; 134 | } 135 | break; 136 | case state::eof: 137 | { 138 | } 139 | break; 140 | } 141 | } 142 | 143 | private: 144 | void signal_split() { 145 | switch(state_) { 146 | case state::buffering: 147 | { 148 | context_.signal_split(); 149 | drop_buffer(overlap_front_*transport_packet::size); 150 | } 151 | break; 152 | case state::writing: 153 | { 154 | context_.signal_split(); 155 | state_ = state::buffering2; 156 | } 157 | break; 158 | case state::buffering2: 159 | { 160 | } 161 | break; 162 | case state::eof: 163 | { 164 | } 165 | break; 166 | } 167 | } 168 | 169 | void flush_buffer() { 170 | buffer_.exceptions( 171 | std::ios_base::failbit | 172 | std::ios_base::badbit); 173 | // because a joint file position is maintained by std::basic_filebuf 174 | buffer_.seekg(input_pos_); 175 | std::copy( 176 | istreambuf_iterator(buffer_), 177 | istreambuf_iterator(), 178 | ostreambuf_iterator(output_)); 179 | buffer_.clear(); // clear eofbit 180 | input_pos_ = buffer_.tellg(); 181 | } 182 | 183 | void drop_buffer(size_t remain_bytes) { 184 | buffer_.exceptions( 185 | std::ios_base::failbit | 186 | std::ios_base::badbit); 187 | auto end_of_buffer_pos = buffer_.tellp(); 188 | input_pos_ = 189 | std::max( 190 | end_of_buffer_pos - static_cast(remain_bytes), 191 | input_pos_); 192 | } 193 | 194 | private: 195 | std::ostream& output_; 196 | std::iostream& buffer_; 197 | std::iostream::pos_type input_pos_; 198 | splitter_context context_; 199 | state state_; 200 | bool enable_pmt_separator_; 201 | bool enable_eit_separator_; 202 | int overlap_front_; 203 | int overlap_back_; 204 | int written_overlap_back_; 205 | }; 206 | 207 | } 208 | 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /tsdivider.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_SCOPE_EXIT_CONFIG_USE_LAMBDAS 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | namespace po = boost::program_options; 11 | namespace fs = boost::filesystem; 12 | #include "picojson.h" 13 | 14 | #include "ts_reader.hpp" 15 | #include "context.hpp" 16 | #include "view.hpp" 17 | #include "ts_trimmer.hpp" 18 | #include "wrap_around_time_stamp.hpp" 19 | 20 | 21 | bool checkProgramOptions(const po::variables_map& vm) { 22 | if(vm.count("help")) 23 | return false; 24 | 25 | if(!vm.count("input") && !vm.count("version")) 26 | return false; 27 | 28 | return true; 29 | } 30 | 31 | int main(int argc, char* argv[]) { 32 | po::options_description desc("options"); 33 | desc.add_options() 34 | ("help", "produce help message") 35 | ("version,v", "print version") 36 | ("input,i", po::value(), "input file (REQUIRED)") 37 | ("output,o", po::value(), "output file") 38 | ("tmpbuf", po::value(), "temporary buffer file (default: \"${--output}.tmpbuf\"") 39 | ("json", "print information by json") 40 | ("json_prettify", "print information by prettify json") 41 | ("debug", "print information by debug view") 42 | ("header", "print section header") 43 | ("pat", "print pat") 44 | ("pmt", "print pmt") 45 | ("sdt", "print sdt") 46 | ("tot", "print tot") 47 | ("eit", "print eit") 48 | ("print_if_changed", "print information if section version changed") 49 | ("packet_num", "print ts packet number") 50 | ("enable_pmt_separator", po::value()->default_value(true), "") 51 | ("enable_eit_separator", po::value()->default_value(true), "") 52 | ("trim_threshold", po::value()->default_value(5*60), "(sec)") 53 | ("overlap_front", po::value()->default_value(1024), "(packet)") 54 | ("overlap_back", po::value()->default_value(1024), "(packet)") 55 | ("prettify", "prettify json") 56 | ("broadcast_time", "print broadcast time") 57 | ("program_info", "print program information") 58 | ("transport_stream_id", "print transport stream id") 59 | ; 60 | 61 | po::variables_map vm; 62 | po::store(po::parse_command_line(argc, argv, desc), vm); 63 | po::notify(vm); 64 | 65 | if(!checkProgramOptions(vm)) { 66 | cout << desc << endl; 67 | return 1; 68 | } 69 | 70 | if(vm.count("version")) { 71 | cout << "tsdivider version " << VERSION << endl; 72 | return 0; 73 | } 74 | 75 | bool view_flag = true; 76 | std::unique_ptr view; 77 | if(vm.count("json")) 78 | view.reset(new tsd::json_view()); 79 | else if(vm.count("json_prettify")) 80 | view.reset(new tsd::json_view(true)); 81 | else if(vm.count("debug")) 82 | view.reset(new tsd::debug_view()); 83 | else { 84 | view.reset(new tsd::view()); 85 | view_flag = false; 86 | } 87 | view->set_print_section_header(vm.count("header")); 88 | view->set_print_pat(vm.count("pat")); 89 | view->set_print_pmt(vm.count("pmt")); 90 | view->set_print_sdt(vm.count("sdt")); 91 | view->set_print_tot(vm.count("tot")); 92 | view->set_print_eit(vm.count("eit")); 93 | view->set_print_if_changed(vm.count("print_if_changed")); 94 | view->set_print_packet_num(vm.count("packet_num")); 95 | 96 | try { 97 | std::ifstream input( 98 | vm["input"].as(), 99 | std::ios::binary); 100 | input.exceptions( 101 | std::ios_base::failbit | std::ios_base::badbit); 102 | 103 | tsd::tsreader reader(input); 104 | tsd::transport_packet packet; 105 | tsd::context cxt(std::move(view)); 106 | 107 | std::ofstream output; 108 | output.exceptions( 109 | std::ios_base::failbit | std::ios_base::badbit); 110 | 111 | std::fstream fbuffer; 112 | fbuffer.exceptions( 113 | std::ios_base::failbit | std::ios_base::badbit); 114 | fs::path fbuffer_path; 115 | 116 | BOOST_SCOPE_EXIT(&fbuffer, &fbuffer_path) { 117 | if(!fbuffer_path.empty()) { 118 | fbuffer.exceptions(std::ios_base::goodbit); 119 | fbuffer.close(); 120 | try { 121 | if(fs::exists(fbuffer_path)) 122 | fs::remove(fbuffer_path); 123 | } 124 | catch(fs::filesystem_error& e) { 125 | cerr << e.what() << endl; 126 | } 127 | } 128 | }; 129 | 130 | if(vm.count("output")) { 131 | output.open( 132 | vm["output"].as(), 133 | std::ios::binary | std::ios::trunc); 134 | 135 | if(vm.count("tmpbuf")) { 136 | fbuffer_path = (vm["tmpbuf"].as()); 137 | } 138 | else { 139 | fbuffer_path = 140 | std::string(vm["output"].as()) + ".tmpbuf"; 141 | } 142 | fbuffer.open( 143 | fbuffer_path.string(), 144 | std::ios_base::binary | 145 | std::ios_base::trunc | 146 | std::ios_base::in | 147 | std::ios_base::out); 148 | 149 | std::unique_ptr trimmer( 150 | new tsd::ts_trimmer( 151 | output, 152 | fbuffer, 153 | vm["trim_threshold"].as(), 154 | vm["enable_pmt_separator"].as(), 155 | vm["enable_eit_separator"].as(), 156 | vm["overlap_front"].as(), 157 | vm["overlap_back"].as())); 158 | cxt.set_ts_trimmer(std::move(trimmer)); 159 | } 160 | 161 | picojson::object root; 162 | bool print_program_info_latch = vm.count("program_info"); 163 | bool print_tsid_latch = vm.count("transport_stream_id"); 164 | 165 | while(reader.next(packet)) { 166 | cxt.handle_packet(packet); 167 | 168 | if(print_program_info_latch) { 169 | if(!cxt.service_descriptors.empty()) { 170 | picojson::array program_info; 171 | char tmpbuf[4096]; 172 | 173 | for(auto& kv : cxt.service_descriptors) { 174 | picojson::object sdo; 175 | sdo.emplace( 176 | "program_number", 177 | picojson::value(static_cast(kv.first))); 178 | AribToString( 179 | tmpbuf, 180 | kv.second.service_name.data(), 181 | kv.second.service_name.size()); 182 | sdo.emplace( 183 | "service_name", 184 | picojson::value(tmpbuf)); 185 | AribToString( 186 | tmpbuf, 187 | kv.second.service_provider_name.data(), 188 | kv.second.service_provider_name.size()); 189 | sdo.emplace( 190 | "service_provider", 191 | picojson::value(tmpbuf)); 192 | program_info.emplace_back(std::move(sdo)); 193 | } 194 | 195 | root.emplace( 196 | "program_info", 197 | picojson::value(program_info)); 198 | print_program_info_latch = false; 199 | } 200 | } 201 | 202 | if(print_tsid_latch) { 203 | if(cxt.transport_stream_id) { 204 | root.emplace( 205 | "transport_stream_id", 206 | picojson::value( 207 | static_cast(*cxt.transport_stream_id))); 208 | print_tsid_latch = false; 209 | } 210 | } 211 | 212 | if(!vm.count("output") && 213 | !print_program_info_latch && 214 | !print_tsid_latch && 215 | !view_flag) { 216 | if(vm.count("broadcast_time")) { 217 | if(cxt.first_pcr && 218 | cxt.latest_pcr && 219 | cxt.baseline_pcr && 220 | cxt.baseline_time) { 221 | uint16_t current_pcr = *cxt.latest_pcr; 222 | auto current_pos = reader.tellg(); 223 | 224 | reader.seekg( 225 | -4092 * tsd::transport_packet::size, 226 | std::ios_base::end); 227 | 228 | while(reader.next(packet)) { 229 | cxt.handle_packet(packet); 230 | } 231 | 232 | if(*cxt.latest_pcr != current_pcr) 233 | break; 234 | else { 235 | reader.seekg(0, std::ios_base::beg); 236 | cxt.clear(); 237 | 238 | while(reader.next(packet)) { 239 | cxt.handle_packet(packet); 240 | } 241 | } 242 | } 243 | } 244 | else { 245 | break; 246 | } 247 | } 248 | } 249 | 250 | if(vm.count("broadcast_time")) { 251 | if(cxt.first_pcr && 252 | cxt.latest_pcr && 253 | cxt.baseline_pcr && 254 | cxt.baseline_time) { 255 | picojson::object broadcast_time_o; 256 | tsd::wrap_around_time_stamp t0(*cxt.first_pcr); 257 | tsd::wrap_around_time_stamp tb(*cxt.baseline_pcr); 258 | tsd::wrap_around_time_stamp t1(*cxt.latest_pcr); 259 | time_t broadcast_begin = 260 | *cxt.baseline_time - ((tb - t0) / 90000); 261 | time_t broadcast_end = 262 | broadcast_begin + ((t1 - t0) / 90000); 263 | char tmpbuf[100]; 264 | std::strftime( 265 | tmpbuf, 266 | sizeof(tmpbuf), 267 | "%c %Z", 268 | std::localtime(&broadcast_begin)); 269 | broadcast_time_o.emplace("begin", picojson::value(tmpbuf)); 270 | std::strftime( 271 | tmpbuf, 272 | sizeof(tmpbuf), 273 | "%c %Z", 274 | std::localtime(&broadcast_end)); 275 | broadcast_time_o.emplace("end", picojson::value(tmpbuf)); 276 | double duration = (t1 - t0) / 90000.0; 277 | broadcast_time_o.emplace("duration", picojson::value(duration)); 278 | 279 | root.emplace( 280 | "broadcast_time", 281 | picojson::value(broadcast_time_o)); 282 | } 283 | } 284 | 285 | // print information 286 | if(!root.empty()) { 287 | cout << picojson::value(root).serialize(static_cast(vm.count("prettify"))) << endl; 288 | } 289 | } 290 | catch(const std::ios_base::failure& e) { 291 | cerr << "error: " << e.what() << endl; 292 | return 1; 293 | } 294 | 295 | return 0; 296 | } 297 | -------------------------------------------------------------------------------- /util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_UTIL_HPP_ 2 | #define _TSD_UTIL_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace tsd 9 | { 10 | 11 | inline 12 | uint8_t get8(const uint8_t* p) { 13 | return *p; 14 | } 15 | 16 | inline 17 | uint16_t get16(const uint8_t* p) { 18 | return (get8(p) << 8) | get8(p+1); 19 | } 20 | 21 | inline 22 | uint32_t get32(const uint8_t* p) { 23 | return (get16(p) << 16) | get16(p+2); 24 | } 25 | 26 | inline 27 | uint8_t get8(const char* p) { 28 | return *reinterpret_cast(p); 29 | } 30 | 31 | inline 32 | uint16_t get16(const char* p) { 33 | return get16(reinterpret_cast(p)); 34 | } 35 | 36 | inline 37 | uint32_t get32(const char* p) { 38 | return get32(reinterpret_cast(p)); 39 | } 40 | 41 | inline 42 | void hexdump(const char* data, size_t size, ostream& ost) { 43 | size_t i; 44 | for(i = 0; i < size; ++i){ 45 | ost 46 | << std::setw(2) 47 | << std::setfill('0') 48 | << std::hex 49 | << std::uppercase 50 | << static_cast(get8(data+i)) 51 | << ' '; 52 | if(i % 16 == 15) 53 | ost << endl; 54 | } 55 | if(i % 16 != 0) 56 | ost << endl; 57 | } 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /view.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_VIEW_HPP_ 2 | #define _TSD_VIEW_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "picojson.h" 9 | #include "aribstr.h" 10 | #include "util.hpp" 11 | #include "section_header.hpp" 12 | #include "pat.hpp" 13 | #include "pmt.hpp" 14 | #include "sdt.hpp" 15 | #include "tot.hpp" 16 | #include "eit.hpp" 17 | #include "descriptor.hpp" 18 | 19 | namespace tsd 20 | { 21 | 22 | class view 23 | { 24 | public: 25 | view() : 26 | print_section_header_(false), 27 | print_pat_(false), 28 | print_pmt_(false), 29 | print_sdt_(false), 30 | print_tot_(false), 31 | print_eit_(false), 32 | print_if_changed_(false), 33 | print_packet_num_(false) 34 | {} 35 | 36 | virtual ~view() {} 37 | 38 | void set_print_section_header(bool p) { 39 | print_section_header_ = p; 40 | } 41 | void set_print_pat(bool p) { 42 | print_pat_ = p; 43 | } 44 | void set_print_pmt(bool p) { 45 | print_pmt_ = p; 46 | } 47 | void set_print_sdt(bool p) { 48 | print_sdt_ = p; 49 | } 50 | void set_print_tot(bool p) { 51 | print_tot_ = p; 52 | } 53 | void set_print_eit(bool p) { 54 | print_eit_ = p; 55 | } 56 | void set_print_if_changed(bool p) { 57 | print_if_changed_ = p; 58 | } 59 | void set_print_packet_num(bool p) { 60 | print_packet_num_ = p; 61 | } 62 | 63 | void print( 64 | uint64_t packet_num, 65 | const section_header& header, 66 | const program_association_table& pat, 67 | bool changed = true) const { 68 | if(print_if_changed_ && !changed) 69 | return; 70 | if(print_pat_) { 71 | print_packet_num(packet_num); 72 | print_section_header(header); 73 | on_print(pat); 74 | } 75 | } 76 | void print( 77 | uint64_t packet_num, 78 | const section_header& header, 79 | const program_map_table& pmt, 80 | bool changed = true) const { 81 | if(print_if_changed_ && !changed) 82 | return; 83 | if(print_pmt_) { 84 | print_packet_num(packet_num); 85 | print_section_header(header); 86 | on_print(pmt); 87 | } 88 | } 89 | void print( 90 | uint64_t packet_num, 91 | const section_header& header, 92 | const service_description_table& sdt, 93 | bool changed = true) const { 94 | if(print_if_changed_ && !changed) 95 | return; 96 | if(print_sdt_) { 97 | print_packet_num(packet_num); 98 | print_section_header(header); 99 | on_print(sdt); 100 | } 101 | } 102 | void print( 103 | uint64_t packet_num, 104 | const section_header& header, 105 | const time_offset_table& tot, 106 | bool changed = true) const { 107 | if(print_if_changed_ && !changed) 108 | return; 109 | if(print_tot_) { 110 | print_packet_num(packet_num); 111 | print_section_header(header); 112 | on_print(tot); 113 | } 114 | } 115 | void print( 116 | uint64_t packet_num, 117 | const section_header& header, 118 | const event_information_table& eit, 119 | bool changed = true) const { 120 | if(print_if_changed_ && !changed) 121 | return; 122 | if(print_eit_) { 123 | print_packet_num(packet_num); 124 | print_section_header(header); 125 | on_print(eit); 126 | } 127 | } 128 | 129 | private: 130 | void print_packet_num(uint64_t n) const { 131 | if(print_packet_num_) 132 | on_print_packet_num(n); 133 | } 134 | 135 | void print_section_header(const section_header& h) const { 136 | if(print_section_header_) 137 | on_print_section_header(h); 138 | } 139 | 140 | protected: 141 | virtual void on_print_packet_num(uint64_t n) const { 142 | cout << std::dec << n << "\t"; 143 | } 144 | 145 | virtual void on_print_section_header(const section_header& header) const {} 146 | virtual void on_print(const program_association_table& pat) const {} 147 | virtual void on_print(const program_map_table& pmt) const {} 148 | virtual void on_print(const service_description_table& sdt) const {} 149 | virtual void on_print(const time_offset_table& tot) const {} 150 | virtual void on_print(const event_information_table& eit) const {} 151 | 152 | protected: 153 | bool print_section_header_; 154 | bool print_pat_; 155 | bool print_pmt_; 156 | bool print_sdt_; 157 | bool print_tot_; 158 | bool print_eit_; 159 | bool print_if_changed_; 160 | bool print_packet_num_; 161 | }; 162 | 163 | 164 | class json_view : public view 165 | { 166 | public: 167 | json_view() : 168 | prettify_(false) {} 169 | explicit json_view(bool prettify) : 170 | prettify_(prettify) {} 171 | virtual ~json_view() {} 172 | 173 | protected: 174 | virtual void on_print_section_header(const section_header& h) const { 175 | cout << serialize_section_header(h).serialize(prettify_); 176 | } 177 | 178 | virtual void on_print(const program_association_table& pat) const { 179 | picojson::object o; 180 | picojson::array association; 181 | 182 | for(auto& i : pat.association) { 183 | picojson::object program_to_pid_obj; 184 | program_to_pid_obj.emplace( 185 | "program_number", picojson::value(d(i.program_number))); 186 | program_to_pid_obj.emplace( 187 | "pmt_pid", picojson::value(d(i.pmt_pid))); 188 | association.emplace_back( 189 | picojson::value(program_to_pid_obj)); 190 | } 191 | 192 | o.emplace( 193 | "association", 194 | picojson::value(association)); 195 | 196 | cout << picojson::value(o).serialize(prettify_) << endl; 197 | } 198 | 199 | virtual void on_print(const program_map_table& pmt) const { 200 | picojson::object o; 201 | o.emplace( 202 | "pcr_pid", 203 | picojson::value(d(pmt.pcr_pid))); 204 | 205 | picojson::array program_info; 206 | for(auto& pi : pmt.program_info) { 207 | picojson::object pio; 208 | pio.emplace("tag", picojson::value(d(pi.tag))); 209 | program_info.emplace_back(picojson::value(pio)); 210 | } 211 | o.emplace("program_info", picojson::value(program_info)); 212 | 213 | picojson::array program_elements; 214 | for(auto& pe : pmt.program_elements) { 215 | picojson::object peo; 216 | peo.emplace("stream_type", picojson::value(d(pe.stream_type))); 217 | peo.emplace("elementary_pid", picojson::value(d(pe.elementary_pid))); 218 | picojson::array es_info; 219 | for(auto& desc : pe.es_info) { 220 | picojson::object es_info_o; 221 | es_info_o.emplace("tag", picojson::value(d(desc.tag))); 222 | if(desc.tag == stream_identifier_descriptor::TAG) { 223 | auto sid = desc.as(); 224 | es_info_o.emplace("component_tag", picojson::value(d(sid.component_tag))); 225 | } 226 | es_info.emplace_back(picojson::value(es_info_o)); 227 | } 228 | peo.emplace("es_info", picojson::value(es_info)); 229 | program_elements.emplace_back(picojson::value(peo)); 230 | } 231 | o.emplace("program_elements", picojson::value(program_elements)); 232 | 233 | cout << picojson::value(o).serialize(prettify_) << endl; 234 | } 235 | 236 | virtual void on_print(const service_description_table& sdt) const { 237 | char tmpbuf[4096]; 238 | picojson::object o; 239 | o.emplace( 240 | "original_network_id", 241 | picojson::value(d(sdt.original_network_id))); 242 | 243 | picojson::array services; 244 | for(auto& s : sdt.services) { 245 | picojson::object sobj; 246 | sobj.emplace("service_id", picojson::value(d(s.service_id))); 247 | picojson::array descriptors; 248 | for(auto& desc : s.descriptors) { 249 | if(desc.tag == service_descriptor::TAG) { 250 | auto sd = desc.as(); 251 | picojson::object dobj; 252 | dobj.emplace("service_type", picojson::value(d(sd.service_type))); 253 | AribToString( 254 | tmpbuf, 255 | sd.service_provider_name.data(), 256 | sd.service_provider_name.size()); 257 | dobj.emplace("provider_name", picojson::value(tmpbuf)); 258 | AribToString( 259 | tmpbuf, 260 | sd.service_name.data(), 261 | sd.service_name.size()); 262 | dobj.emplace("service_name", picojson::value(tmpbuf)); 263 | descriptors.emplace_back(picojson::value(dobj)); 264 | } 265 | } 266 | sobj.emplace("descriptors", picojson::value(descriptors)); 267 | services.emplace_back(picojson::value(sobj)); 268 | } 269 | o.emplace("services", picojson::value(services)); 270 | cout << picojson::value(o).serialize(prettify_) << endl; 271 | } 272 | 273 | virtual void on_print(const time_offset_table& tot) const { 274 | picojson::object o; 275 | time_t t = tot.time.to_time_t(); 276 | char tmpbuf[100]; 277 | std::strftime(tmpbuf, sizeof(tmpbuf), "%c %Z", std::localtime(&t)); 278 | o.emplace("jst_time", picojson::value(tmpbuf)); 279 | cout << picojson::value(o).serialize(prettify_) << endl; 280 | } 281 | 282 | virtual void on_print(const event_information_table& eit) const { 283 | picojson::object rooto; 284 | rooto.emplace( 285 | "transport_stream_id", picojson::value(d(eit.transport_stream_id))); 286 | rooto.emplace( 287 | "original_network_id", picojson::value(d(eit.original_network_id))); 288 | rooto.emplace( 289 | "segment_last_section_number", picojson::value(d(eit.segment_last_section_number))); 290 | rooto.emplace( 291 | "last_table_id", picojson::value(d(eit.last_table_id))); 292 | 293 | std::ostringstream oss; 294 | char tmpbuf[4096]; 295 | time_t t; 296 | picojson::array events; 297 | for(auto& e : eit.events) { 298 | picojson::object eo; 299 | eo.emplace("event_id", picojson::value(d(e.event_id))); 300 | t = e.start_time.to_time_t(); 301 | std::strftime(tmpbuf, sizeof(tmpbuf), "%c %Z", std::localtime(&t)); 302 | eo.emplace("start_time", picojson::value(tmpbuf)); 303 | oss.str(""); 304 | oss 305 | << static_cast(e.duration.hour) << ':' 306 | << static_cast(e.duration.min) << ':' 307 | << static_cast(e.duration.sec); 308 | eo.emplace( 309 | "duration", picojson::value(oss.str())); 310 | eo.emplace( 311 | "running_status", picojson::value(d(e.running_status))); 312 | eo.emplace( 313 | "free_ca_mode", picojson::value(static_cast(e.free_ca_mode))); 314 | 315 | picojson::array descriptors; 316 | for(auto& desc : e.descriptors) { 317 | picojson::object dobj; 318 | dobj.emplace("tag", picojson::value(d(desc.tag))); 319 | if(desc.tag == short_event_descriptor::TAG) { 320 | auto sed = desc.as(); 321 | dobj.emplace( 322 | "iso_639_language_code", 323 | picojson::value(sed.iso_639_language_code)); 324 | AribToString( 325 | tmpbuf, 326 | sed.event_name.data(), 327 | sed.event_name.size()); 328 | dobj.emplace( 329 | "event_name", 330 | picojson::value(tmpbuf)); 331 | AribToString( 332 | tmpbuf, 333 | sed.text.data(), 334 | sed.text.size()); 335 | dobj.emplace( 336 | "text", 337 | picojson::value(tmpbuf)); 338 | } 339 | descriptors.emplace_back(picojson::value(dobj)); 340 | } 341 | eo.emplace("descriptors", picojson::value(descriptors)); 342 | events.emplace_back(picojson::value(eo)); 343 | } 344 | rooto.emplace("events", picojson::value(events)); 345 | 346 | cout << picojson::value(rooto).serialize(prettify_) << endl; 347 | } 348 | 349 | private: 350 | picojson::value serialize_section_header( 351 | const section_header& sh) const { 352 | picojson::object o; 353 | o.emplace( 354 | "table_id", picojson::value(d(sh.table_id))); 355 | if(sh.section_syntax_indicator) { 356 | o.emplace( 357 | "table_id_extension", picojson::value(d(sh.table_id_extension))); 358 | o.emplace( 359 | "version", picojson::value(d(sh.version))); 360 | o.emplace( 361 | "current_next_indicator", picojson::value(d(sh.current_next_indicator))); 362 | o.emplace( 363 | "section_number", picojson::value(d(sh.section_number))); 364 | o.emplace( 365 | "last_section_number", picojson::value(d(sh.section_number))); 366 | } 367 | return picojson::value(o); 368 | } 369 | 370 | template 371 | double d(const D& d) const { 372 | return static_cast(d); 373 | } 374 | 375 | private: 376 | bool prettify_; 377 | 378 | }; 379 | 380 | 381 | class debug_view : public view 382 | { 383 | public: 384 | virtual ~debug_view() {} 385 | 386 | protected: 387 | virtual void on_print_section_header(const section_header& h) const { 388 | cout << "-----section header-----" << endl; 389 | dump_section_header(h); 390 | } 391 | 392 | virtual void on_print(const program_association_table& pat) const { 393 | cout << "----- pat -----" << endl; 394 | for(auto& i : pat.association) { 395 | cout << "[program : " << i.program_number; 396 | cout << ", pid : " << i.pmt_pid << "]" << endl; 397 | } 398 | } 399 | 400 | virtual void on_print(const program_map_table& pmt) const { 401 | cout << "----- pmt -----" << endl; 402 | cout << "pcr_pid : " << (int)pmt.pcr_pid << endl; 403 | cout << "program_info(descriptor)" << endl; 404 | { 405 | for(auto& i : pmt.program_info) { 406 | cout << "\t" << "tag : " << (int)i.tag << endl; 407 | cout << "\t" << "length : " << (int)i.length << endl; 408 | } 409 | } 410 | cout << "program_elements" << endl; 411 | { 412 | for(auto& i : pmt.program_elements) { 413 | cout << "\t" << "stream_type : " << (int)i.stream_type << endl; 414 | cout << "\t" << "elementary_pid : " << (int)i.elementary_pid << endl; 415 | cout << "\t" << "es_info(descriptor)" << endl; 416 | for(auto& j : i.es_info) { 417 | cout << "\t\t" << "tag : " << (int)j.tag << endl; 418 | cout << "\t\t" << "length : " << (int)j.length << endl; 419 | } 420 | } 421 | } 422 | } 423 | 424 | virtual void on_print(const service_description_table& sdt) const { 425 | cout << "----SDT sectoin----" << endl; 426 | char tmpbuf[4096]; 427 | cout << "services : " << endl; 428 | for(auto& s : sdt.services) { 429 | cout << "\t" << "service_id : " << (int)s.service_id << endl; 430 | for(auto& d : s.descriptors) { 431 | cout << "\t\t" << "tag : " << (int)d.tag << endl; 432 | cout << "\t\t" << "length : " << (int)d.length << endl; 433 | if(d.tag == service_descriptor::TAG) { 434 | auto sd = d.as(); 435 | cout << "\t\t" << "service_type: " << (int)sd.service_type << endl; 436 | AribToString( 437 | tmpbuf, 438 | sd.service_provider_name.data(), 439 | sd.service_provider_name.size()); 440 | cout << "\t\t" << "service_provider_name: " << tmpbuf << endl; 441 | AribToString( 442 | tmpbuf, 443 | sd.service_name.data(), 444 | sd.service_name.size()); 445 | cout << "\t\t" << "service_name: " << tmpbuf << endl; 446 | } 447 | } 448 | } 449 | } 450 | 451 | virtual void on_print(const time_offset_table& tot) const { 452 | cout << "----- tot section -----" << endl; 453 | cout << dec; 454 | time_t t = tot.time.to_time_t(); 455 | char tmpbuf[100]; 456 | std::strftime(tmpbuf, sizeof(tmpbuf), "%c %Z", std::localtime(&t)); 457 | cout << "time : " << tmpbuf << endl; 458 | } 459 | 460 | virtual void on_print(const event_information_table& eit) const { 461 | cout << "----- EIT section -----" << endl; 462 | } 463 | 464 | private: 465 | void dump_section_header(const section_header& sh) const { 466 | cout << "table id : " << (int)sh.table_id << endl; 467 | if(sh.section_syntax_indicator) { 468 | cout << "table_id_extension : " << (int)sh.table_id_extension << endl; 469 | cout << "version : " << (int)sh.version << endl; 470 | cout << "current_next_indicator : " << (int)sh.current_next_indicator << endl; 471 | cout << "section number : " << (int)sh.section_number << endl; 472 | cout << "last section number : " << (int)sh.last_section_number << endl; 473 | } 474 | } 475 | }; 476 | 477 | } 478 | 479 | #endif 480 | -------------------------------------------------------------------------------- /wrap_around_time_stamp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TSD_WRAP_AROUND_TIME_STAMP_HPP 2 | #define _TSD_WRAP_AROUND_TIME_STAMP_HPP 3 | 4 | 5 | namespace tsd 6 | { 7 | class wrap_around_time_stamp 8 | { 9 | public: 10 | static constexpr int64_t max = 0x1FFFFFFFF; 11 | 12 | public: 13 | wrap_around_time_stamp() : 14 | time_(0) {} 15 | explicit wrap_around_time_stamp(int64_t t) : 16 | time_(t) {} 17 | explicit wrap_around_time_stamp(uint64_t t) : 18 | time_(t) {} 19 | 20 | int64_t get() const { 21 | return time_; 22 | } 23 | 24 | const int64_t operator-( 25 | const wrap_around_time_stamp& o) const { 26 | if(std::abs(time_ - o.time_) <= max/2) { 27 | return time_ - o.time_; 28 | } 29 | else { 30 | if(time_ < o.time_) 31 | return (time_+max+1) - o.time_; 32 | else 33 | return time_ - (o.time_+max+1); 34 | } 35 | } 36 | 37 | bool operator<(const wrap_around_time_stamp& o) const { 38 | if(std::abs(time_ - o.time_) <= max/2) 39 | return time_ < o.time_; 40 | else 41 | return o.time_ < time_; 42 | } 43 | 44 | 45 | private: 46 | int64_t time_; 47 | }; 48 | 49 | } 50 | 51 | 52 | #endif 53 | --------------------------------------------------------------------------------